changes: Bump to 3.8.1
[platform/upstream/evolution-data-server.git] / libedataserver / e-source-authentication.c
1 /*
2  * e-source-authentication.c
3  *
4  * This library is free software you can redistribute it and/or modify it
5  * under the terms of the GNU Lesser General Public License as published by
6  * the Free Software Foundation.
7  *
8  * This library is distributed in the hope that it will be useful, but
9  * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
10  * or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
11  * for more details.
12  *
13  * You should have received a copy of the GNU Lesser General Public License
14  * along with this library; if not, see <http://www.gnu.org/licenses/>.
15  *
16  */
17
18 /**
19  * SECTION: e-source-authentication
20  * @include: libedataserver/libedataserver.h
21  * @short_description: #ESource extension for authentication settings
22  *
23  * The #ESourceAuthentication extension tracks authentication settings
24  * for a user account on a remote server.
25  *
26  * Access the extension as follows:
27  *
28  * |[
29  *   #include <libedataserver/libedataserver.h>
30  *
31  *   ESourceAuthentication *extension;
32  *
33  *   extension = e_source_get_extension (source, E_SOURCE_EXTENSION_AUTHENTICATION);
34  * ]|
35  **/
36
37 #include "e-source-authentication.h"
38
39 #include <libedataserver/e-data-server-util.h>
40
41 #define E_SOURCE_AUTHENTICATION_GET_PRIVATE(obj) \
42         (G_TYPE_INSTANCE_GET_PRIVATE \
43         ((obj), E_TYPE_SOURCE_AUTHENTICATION, ESourceAuthenticationPrivate))
44
45 struct _ESourceAuthenticationPrivate {
46         GMutex property_lock;
47         gchar *host;
48         gchar *method;
49         guint16 port;
50         gchar *proxy_uid;
51         gboolean remember_password;
52         gchar *user;
53
54         /* GNetworkAddress caches data internally, so we maintain the
55          * instance to preserve the cache as opposed to just creating
56          * a new GNetworkAddress instance each time it's requested. */
57         GSocketConnectable *connectable;
58 };
59
60 enum {
61         PROP_0,
62         PROP_CONNECTABLE,
63         PROP_HOST,
64         PROP_METHOD,
65         PROP_PORT,
66         PROP_PROXY_UID,
67         PROP_REMEMBER_PASSWORD,
68         PROP_USER
69 };
70
71 G_DEFINE_TYPE (
72         ESourceAuthentication,
73         e_source_authentication,
74         E_TYPE_SOURCE_EXTENSION)
75
76 static void
77 source_authentication_update_connectable (ESourceAuthentication *extension)
78 {
79         const gchar *host;
80         guint16 port;
81
82         /* This MUST be called with the property_lock acquired. */
83
84         g_clear_object (&extension->priv->connectable);
85
86         host = e_source_authentication_get_host (extension);
87         port = e_source_authentication_get_port (extension);
88
89         if (host != NULL) {
90                 GSocketConnectable *connectable;
91                 connectable = g_network_address_new (host, port);
92                 extension->priv->connectable = connectable;
93         }
94 }
95
96 static void
97 source_authentication_set_property (GObject *object,
98                                     guint property_id,
99                                     const GValue *value,
100                                     GParamSpec *pspec)
101 {
102         switch (property_id) {
103                 case PROP_HOST:
104                         e_source_authentication_set_host (
105                                 E_SOURCE_AUTHENTICATION (object),
106                                 g_value_get_string (value));
107                         return;
108
109                 case PROP_METHOD:
110                         e_source_authentication_set_method (
111                                 E_SOURCE_AUTHENTICATION (object),
112                                 g_value_get_string (value));
113                         return;
114
115                 case PROP_PORT:
116                         e_source_authentication_set_port (
117                                 E_SOURCE_AUTHENTICATION (object),
118                                 g_value_get_uint (value));
119                         return;
120
121                 case PROP_PROXY_UID:
122                         e_source_authentication_set_proxy_uid (
123                                 E_SOURCE_AUTHENTICATION (object),
124                                 g_value_get_string (value));
125                         return;
126
127                 case PROP_REMEMBER_PASSWORD:
128                         e_source_authentication_set_remember_password (
129                                 E_SOURCE_AUTHENTICATION (object),
130                                 g_value_get_boolean (value));
131                         return;
132
133                 case PROP_USER:
134                         e_source_authentication_set_user (
135                                 E_SOURCE_AUTHENTICATION (object),
136                                 g_value_get_string (value));
137                         return;
138         }
139
140         G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
141 }
142
143 static void
144 source_authentication_get_property (GObject *object,
145                                     guint property_id,
146                                     GValue *value,
147                                     GParamSpec *pspec)
148 {
149         switch (property_id) {
150                 case PROP_CONNECTABLE:
151                         g_value_take_object (
152                                 value,
153                                 e_source_authentication_ref_connectable (
154                                 E_SOURCE_AUTHENTICATION (object)));
155                         return;
156
157                 case PROP_HOST:
158                         g_value_take_string (
159                                 value,
160                                 e_source_authentication_dup_host (
161                                 E_SOURCE_AUTHENTICATION (object)));
162                         return;
163
164                 case PROP_METHOD:
165                         g_value_take_string (
166                                 value,
167                                 e_source_authentication_dup_method (
168                                 E_SOURCE_AUTHENTICATION (object)));
169                         return;
170
171                 case PROP_PORT:
172                         g_value_set_uint (
173                                 value,
174                                 e_source_authentication_get_port (
175                                 E_SOURCE_AUTHENTICATION (object)));
176                         return;
177
178                 case PROP_PROXY_UID:
179                         g_value_take_string (
180                                 value,
181                                 e_source_authentication_dup_proxy_uid (
182                                 E_SOURCE_AUTHENTICATION (object)));
183                         return;
184
185                 case PROP_REMEMBER_PASSWORD:
186                         g_value_set_boolean (
187                                 value,
188                                 e_source_authentication_get_remember_password (
189                                 E_SOURCE_AUTHENTICATION (object)));
190                         return;
191
192                 case PROP_USER:
193                         g_value_take_string (
194                                 value,
195                                 e_source_authentication_dup_user (
196                                 E_SOURCE_AUTHENTICATION (object)));
197                         return;
198         }
199
200         G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
201 }
202
203 static void
204 source_authentication_dispose (GObject *object)
205 {
206         ESourceAuthenticationPrivate *priv;
207
208         priv = E_SOURCE_AUTHENTICATION_GET_PRIVATE (object);
209
210         g_clear_object (&priv->connectable);
211
212         /* Chain up to parent's dispose() method. */
213         G_OBJECT_CLASS (e_source_authentication_parent_class)->dispose (object);
214 }
215
216 static void
217 source_authentication_finalize (GObject *object)
218 {
219         ESourceAuthenticationPrivate *priv;
220
221         priv = E_SOURCE_AUTHENTICATION_GET_PRIVATE (object);
222
223         g_mutex_clear (&priv->property_lock);
224
225         g_free (priv->host);
226         g_free (priv->method);
227         g_free (priv->proxy_uid);
228         g_free (priv->user);
229
230         /* Chain up to parent's finalize() method. */
231         G_OBJECT_CLASS (e_source_authentication_parent_class)->finalize (object);
232 }
233
234 static void
235 e_source_authentication_class_init (ESourceAuthenticationClass *class)
236 {
237         GObjectClass *object_class;
238         ESourceExtensionClass *extension_class;
239
240         g_type_class_add_private (class, sizeof (ESourceAuthenticationPrivate));
241
242         object_class = G_OBJECT_CLASS (class);
243         object_class->set_property = source_authentication_set_property;
244         object_class->get_property = source_authentication_get_property;
245         object_class->dispose = source_authentication_dispose;
246         object_class->finalize = source_authentication_finalize;
247
248         extension_class = E_SOURCE_EXTENSION_CLASS (class);
249         extension_class->name = E_SOURCE_EXTENSION_AUTHENTICATION;
250
251         g_object_class_install_property (
252                 object_class,
253                 PROP_CONNECTABLE,
254                 g_param_spec_object (
255                         "connectable",
256                         "Connectable",
257                         "A GSocketConnectable constructed "
258                         "from the host and port properties",
259                         G_TYPE_SOCKET_CONNECTABLE,
260                         G_PARAM_READABLE |
261                         G_PARAM_STATIC_STRINGS));
262
263         g_object_class_install_property (
264                 object_class,
265                 PROP_HOST,
266                 g_param_spec_string (
267                         "host",
268                         "Host",
269                         "Host name for the remote account",
270                         "",
271                         G_PARAM_READWRITE |
272                         G_PARAM_CONSTRUCT |
273                         G_PARAM_STATIC_STRINGS |
274                         E_SOURCE_PARAM_SETTING));
275
276         g_object_class_install_property (
277                 object_class,
278                 PROP_METHOD,
279                 g_param_spec_string (
280                         "method",
281                         "Method",
282                         "Authentication method",
283                         "none",
284                         G_PARAM_READWRITE |
285                         G_PARAM_CONSTRUCT |
286                         G_PARAM_STATIC_STRINGS |
287                         E_SOURCE_PARAM_SETTING));
288
289         g_object_class_install_property (
290                 object_class,
291                 PROP_PORT,
292                 g_param_spec_uint (
293                         "port",
294                         "Port",
295                         "Port number for the remote account",
296                         0, G_MAXUINT16, 0,
297                         G_PARAM_READWRITE |
298                         G_PARAM_CONSTRUCT |
299                         G_PARAM_STATIC_STRINGS |
300                         E_SOURCE_PARAM_SETTING));
301
302         g_object_class_install_property (
303                 object_class,
304                 PROP_PROXY_UID,
305                 g_param_spec_string (
306                         "proxy-uid",
307                         "Proxy UID",
308                         "ESource UID of a proxy profile",
309                         "system-proxy",
310                         G_PARAM_READWRITE |
311                         G_PARAM_CONSTRUCT |
312                         G_PARAM_STATIC_STRINGS |
313                         E_SOURCE_PARAM_SETTING));
314
315         g_object_class_install_property (
316                 object_class,
317                 PROP_REMEMBER_PASSWORD,
318                 g_param_spec_boolean (
319                         "remember-password",
320                         "Remember Password",
321                         "Whether to offer to remember the "
322                         "password by default when prompted",
323                         TRUE,
324                         G_PARAM_READWRITE |
325                         G_PARAM_CONSTRUCT |
326                         G_PARAM_STATIC_STRINGS |
327                         E_SOURCE_PARAM_SETTING));
328
329         g_object_class_install_property (
330                 object_class,
331                 PROP_USER,
332                 g_param_spec_string (
333                         "user",
334                         "User",
335                         "User name for the remote account",
336                         NULL,
337                         G_PARAM_READWRITE |
338                         G_PARAM_CONSTRUCT |
339                         G_PARAM_STATIC_STRINGS |
340                         E_SOURCE_PARAM_SETTING));
341 }
342
343 static void
344 e_source_authentication_init (ESourceAuthentication *extension)
345 {
346         extension->priv = E_SOURCE_AUTHENTICATION_GET_PRIVATE (extension);
347         g_mutex_init (&extension->priv->property_lock);
348 }
349
350 /**
351  * e_source_authentication_required:
352  * @extension: an #ESourceAuthentication
353  *
354  * This is a convenience function which returns whether authentication
355  * is required at all, regardless of the method used.  This relies on
356  * the convention of setting #ESourceAuthentication:method to "none"
357  * when authentication is <emphasis>not</emphasis> required.
358  *
359  * Returns: whether authentication is required at all
360  *
361  * Since: 3.6
362  **/
363 gboolean
364 e_source_authentication_required (ESourceAuthentication *extension)
365 {
366         const gchar *method;
367
368         g_return_val_if_fail (E_IS_SOURCE_AUTHENTICATION (extension), FALSE);
369
370         method = e_source_authentication_get_method (extension);
371         g_return_val_if_fail (method != NULL && *method != '\0', FALSE);
372
373         return (g_strcmp0 (method, "none") != 0);
374 }
375
376 /**
377  * e_source_authentication_ref_connectable:
378  * @extension: an #ESourceAuthentication
379  *
380  * Returns a #GSocketConnectable instance constructed from @extension's
381  * #ESourceAuthentication:host and #ESourceAuthentication:port properties,
382  * or %NULL if the #ESourceAuthentication:host is not set.
383  *
384  * The returned #GSocketConnectable is referenced for thread-safety and must
385  * be unreferenced with g_object_unref() when finished with it.
386  *
387  * Returns: (transfer full): a #GSocketConnectable, or %NULL
388  *
389  * Since: 3.8
390  **/
391 GSocketConnectable *
392 e_source_authentication_ref_connectable (ESourceAuthentication *extension)
393 {
394         GSocketConnectable *connectable = NULL;
395
396         g_return_val_if_fail (E_IS_SOURCE_AUTHENTICATION (extension), NULL);
397
398         g_mutex_lock (&extension->priv->property_lock);
399
400         if (extension->priv->connectable != NULL)
401                 connectable = g_object_ref (extension->priv->connectable);
402
403         g_mutex_unlock (&extension->priv->property_lock);
404
405         return connectable;
406 }
407
408 /**
409  * e_source_authentication_get_host:
410  * @extension: an #ESourceAuthentication
411  *
412  * Returns the host name used to authenticate to a remote account.
413  *
414  * Returns: the host name of a remote account
415  *
416  * Since: 3.6
417  **/
418 const gchar *
419 e_source_authentication_get_host (ESourceAuthentication *extension)
420 {
421         g_return_val_if_fail (E_IS_SOURCE_AUTHENTICATION (extension), NULL);
422
423         return extension->priv->host;
424 }
425
426 /**
427  * e_source_authentication_dup_host:
428  * @extension: an #ESourceAuthentication
429  *
430  * Thread-safe variation of e_source_authentication_get_host().
431  * Use this function when accessing @extension from multiple threads.
432  *
433  * The returned string should be freed with g_free() when no longer needed.
434  *
435  * Returns: a newly-allocated copy of #ESourceAuthentication:host
436  *
437  * Since: 3.6
438  **/
439 gchar *
440 e_source_authentication_dup_host (ESourceAuthentication *extension)
441 {
442         const gchar *protected;
443         gchar *duplicate;
444
445         g_return_val_if_fail (E_IS_SOURCE_AUTHENTICATION (extension), NULL);
446
447         g_mutex_lock (&extension->priv->property_lock);
448
449         protected = e_source_authentication_get_host (extension);
450         duplicate = g_strdup (protected);
451
452         g_mutex_unlock (&extension->priv->property_lock);
453
454         return duplicate;
455 }
456
457 /**
458  * e_source_authentication_set_host:
459  * @extension: an #ESourceAuthentication
460  * @host: (allow-none): a host name, or %NULL
461  *
462  * Sets the host name used to authenticate to a remote account.
463  *
464  * The internal copy of @host is automatically stripped of leading and
465  * trailing whitespace.  If the resulting string is empty, %NULL is set
466  * instead.
467  *
468  * Since: 3.6
469  **/
470 void
471 e_source_authentication_set_host (ESourceAuthentication *extension,
472                                   const gchar *host)
473 {
474         g_return_if_fail (E_IS_SOURCE_AUTHENTICATION (extension));
475
476         g_mutex_lock (&extension->priv->property_lock);
477
478         if (g_strcmp0 (extension->priv->host, host) == 0) {
479                 g_mutex_unlock (&extension->priv->property_lock);
480                 return;
481         }
482
483         g_free (extension->priv->host);
484         extension->priv->host = e_util_strdup_strip (host);
485
486         source_authentication_update_connectable (extension);
487
488         g_mutex_unlock (&extension->priv->property_lock);
489
490         g_object_notify (G_OBJECT (extension), "host");
491
492         /* Changing the host also changes the connectable. */
493         g_object_notify (G_OBJECT (extension), "connectable");
494 }
495
496 /**
497  * e_source_authentication_get_method:
498  * @extension: an #ESourceAuthentication
499  *
500  * Returns the authentication method for a remote account.  There are
501  * no pre-defined method names; backends are free to set this however
502  * they wish.  If authentication is not required for a remote account,
503  * the convention is to set #ESourceAuthentication:method to "none".
504  *
505  * Returns: the authentication method for a remote account
506  *
507  * Since: 3.6
508  **/
509 const gchar *
510 e_source_authentication_get_method (ESourceAuthentication *extension)
511 {
512         g_return_val_if_fail (E_IS_SOURCE_AUTHENTICATION (extension), NULL);
513
514         return extension->priv->method;
515 }
516
517 /**
518  * e_source_authentication_dup_method:
519  * @extension: an #ESourceAuthentication
520  *
521  * Thread-safe variation of e_source_authentication_get_method().
522  * Use this function when accessing @extension from multiple threads.
523  *
524  * The returned string should be freed with g_free() when no longer needed.
525  *
526  * Returns: a newly-allocated copy of #ESourceAuthentication:method
527  *
528  * Since: 3.6
529  **/
530 gchar *
531 e_source_authentication_dup_method (ESourceAuthentication *extension)
532 {
533         const gchar *protected;
534         gchar *duplicate;
535
536         g_return_val_if_fail (E_IS_SOURCE_AUTHENTICATION (extension), NULL);
537
538         g_mutex_lock (&extension->priv->property_lock);
539
540         protected = e_source_authentication_get_method (extension);
541         duplicate = g_strdup (protected);
542
543         g_mutex_unlock (&extension->priv->property_lock);
544
545         return duplicate;
546 }
547
548 /**
549  * e_source_authentication_set_method:
550  * @extension: an #ESourceAuthentication
551  * @method: (allow-none): authentication method, or %NULL
552  *
553  * Sets the authentication method for a remote account.  There are no
554  * pre-defined method names; backends are free to set this however they
555  * wish.  If authentication is not required for a remote account, the
556  * convention is to set the method to "none".  In keeping with that
557  * convention, #ESourceAuthentication:method will be set to "none" if
558  * @method is %NULL or an empty string.
559  *
560  * Since: 3.6
561  **/
562 void
563 e_source_authentication_set_method (ESourceAuthentication *extension,
564                                     const gchar *method)
565 {
566         g_return_if_fail (E_IS_SOURCE_AUTHENTICATION (extension));
567
568         g_mutex_lock (&extension->priv->property_lock);
569
570         if (g_strcmp0 (extension->priv->method, method) == 0) {
571                 g_mutex_unlock (&extension->priv->property_lock);
572                 return;
573         }
574
575         g_free (extension->priv->method);
576         extension->priv->method = e_util_strdup_strip (method);
577
578         if (extension->priv->method == NULL)
579                 extension->priv->method = g_strdup ("none");
580
581         g_mutex_unlock (&extension->priv->property_lock);
582
583         g_object_notify (G_OBJECT (extension), "method");
584 }
585
586 /**
587  * e_source_authentication_get_port:
588  * @extension: an #ESourceAuthentication
589  *
590  * Returns the port number used to authenticate to a remote account.
591  *
592  * Returns: the port number of a remote account
593  *
594  * Since: 3.6
595  **/
596 guint16
597 e_source_authentication_get_port (ESourceAuthentication *extension)
598 {
599         g_return_val_if_fail (E_IS_SOURCE_AUTHENTICATION (extension), 0);
600
601         return extension->priv->port;
602 }
603
604 /**
605  * e_source_authentication_set_port:
606  * @extension: an #ESourceAuthentication
607  * @port: a port number
608  *
609  * Sets the port number used to authenticate to a remote account.
610  *
611  * Since: 3.6
612  **/
613 void
614 e_source_authentication_set_port (ESourceAuthentication *extension,
615                                   guint16 port)
616 {
617         g_return_if_fail (E_SOURCE_AUTHENTICATION (extension));
618
619         g_mutex_lock (&extension->priv->property_lock);
620
621         if (extension->priv->port == port) {
622                 g_mutex_unlock (&extension->priv->property_lock);
623                 return;
624         }
625
626         extension->priv->port = port;
627
628         source_authentication_update_connectable (extension);
629
630         g_mutex_unlock (&extension->priv->property_lock);
631
632         g_object_notify (G_OBJECT (extension), "port");
633
634         /* Changing the port also changes the connectable. */
635         g_object_notify (G_OBJECT (extension), "connectable");
636 }
637
638 /**
639  * e_source_authentication_get_proxy_uid:
640  * @extension: an #ESourceAuthentication
641  *
642  * Returns the #ESource:uid of the #ESource that holds network proxy
643  * settings for use when connecting to a remote account.
644  *
645  * Returns: the proxy profile #ESource:uid
646  *
647  * Since: 3.12
648  **/
649 const gchar *
650 e_source_authentication_get_proxy_uid (ESourceAuthentication *extension)
651 {
652         g_return_val_if_fail (E_IS_SOURCE_AUTHENTICATION (extension), NULL);
653
654         return extension->priv->proxy_uid;
655 }
656
657 /**
658  * e_source_authentication_dup_proxy_uid:
659  * @extension: an #ESourceAuthentication
660  *
661  * Thread-safe variation of e_source_authentication_get_proxy_uid().
662  * Use this function when accessing @extension from multiple threads.
663  *
664  * The returned string should be freed with g_free() when no longer needed.
665  *
666  * Returns: a newly-allocated copy of #ESourceAuthentication:proxy-uid
667  *
668  * Since: 3.12
669  **/
670 gchar *
671 e_source_authentication_dup_proxy_uid (ESourceAuthentication *extension)
672 {
673         const gchar *protected;
674         gchar *duplicate;
675
676         g_return_val_if_fail (E_IS_SOURCE_AUTHENTICATION (extension), NULL);
677
678         g_mutex_lock (&extension->priv->property_lock);
679
680         protected = e_source_authentication_get_proxy_uid (extension);
681         duplicate = g_strdup (protected);
682
683         g_mutex_unlock (&extension->priv->property_lock);
684
685         return duplicate;
686 }
687
688 /**
689  * e_source_authentication_set_proxy_uid:
690  * @extension: an #ESourceAuthentication
691  * @proxy_uid: the proxy profile #ESource:uid
692  *
693  * Sets the #ESource:uid of the #ESource that holds network proxy settings
694  * for use when connecting to a remote account.
695  *
696  * Since: 3.12
697  **/
698 void
699 e_source_authentication_set_proxy_uid (ESourceAuthentication *extension,
700                                        const gchar *proxy_uid)
701 {
702         g_return_if_fail (E_IS_SOURCE_AUTHENTICATION (extension));
703         g_return_if_fail (proxy_uid != NULL);
704
705         g_mutex_lock (&extension->priv->property_lock);
706
707         if (g_strcmp0 (proxy_uid, extension->priv->proxy_uid) == 0) {
708                 g_mutex_unlock (&extension->priv->property_lock);
709                 return;
710         }
711
712         g_free (extension->priv->proxy_uid);
713         extension->priv->proxy_uid = g_strdup (proxy_uid);
714
715         g_mutex_unlock (&extension->priv->property_lock);
716
717         g_object_notify (G_OBJECT (extension), "proxy-uid");
718 }
719
720 /**
721  * e_source_authentication_get_remember_password:
722  * @extension: an #ESourceAuthentication
723  *
724  * Returns whether to offer to remember the provided password by default
725  * in password prompts.  This way, if the user unchecks the option it will
726  * be unchecked by default in future password prompts.
727  *
728  * Returns: whether to offer to remember the password by default
729  *
730  * Since: 3.10
731  **/
732 gboolean
733 e_source_authentication_get_remember_password (ESourceAuthentication *extension)
734 {
735         g_return_val_if_fail (E_IS_SOURCE_AUTHENTICATION (extension), FALSE);
736
737         return extension->priv->remember_password;
738 }
739
740 /**
741  * e_source_authentication_set_remember_password:
742  * @extension: an #ESourceAuthentication
743  * @remember_password: whether to offer to remember the password by default
744  *
745  * Sets whether to offer to remember the provided password by default in
746  * password prompts.  This way, if the user unchecks the option it will be
747  * unchecked by default in future password prompts.
748  *
749  * Since: 3.10
750  **/
751 void
752 e_source_authentication_set_remember_password (ESourceAuthentication *extension,
753                                                gboolean remember_password)
754 {
755         g_return_if_fail (E_IS_SOURCE_AUTHENTICATION (extension));
756
757         if (extension->priv->remember_password == remember_password)
758                 return;
759
760         extension->priv->remember_password = remember_password;
761
762         g_object_notify (G_OBJECT (extension), "remember-password");
763 }
764
765 /**
766  * e_source_authentication_get_user:
767  * @extension: an #ESourceAuthentication
768  *
769  * Returns the user name used to authenticate to a remote account.
770  *
771  * Returns: the user name of a remote account
772  *
773  * Since: 3.6
774  **/
775 const gchar *
776 e_source_authentication_get_user (ESourceAuthentication *extension)
777 {
778         g_return_val_if_fail (E_IS_SOURCE_AUTHENTICATION (extension), NULL);
779
780         return extension->priv->user;
781 }
782
783 /**
784  * e_source_authentication_dup_user:
785  * @extension: an #ESourceAuthentication
786  *
787  * Thread-safe variation of e_source_authentication_get_user().
788  * Use this function when accessing @extension from multiple threads.
789  *
790  * The returned string should be freed with g_free() when no longer needed.
791  *
792  * Returns: a newly-allocated copy of #ESourceAuthentication:user
793  *
794  * Since: 3.6
795  **/
796 gchar *
797 e_source_authentication_dup_user (ESourceAuthentication *extension)
798 {
799         const gchar *protected;
800         gchar *duplicate;
801
802         g_return_val_if_fail (E_IS_SOURCE_AUTHENTICATION (extension), NULL);
803
804         g_mutex_lock (&extension->priv->property_lock);
805
806         protected = e_source_authentication_get_user (extension);
807         duplicate = g_strdup (protected);
808
809         g_mutex_unlock (&extension->priv->property_lock);
810
811         return duplicate;
812 }
813
814 /**
815  * e_source_authentication_set_user:
816  * @extension: an #ESourceAuthentication
817  * @user: (allow-none): a user name, or %NULL
818  *
819  * Sets the user name used to authenticate to a remote account.
820  *
821  * The internal copy of @user is automatically stripped of leading and
822  * trailing whitespace.  If the resulting string is empty, %NULL is set
823  * instead.
824  *
825  * Since: 3.6
826  **/
827 void
828 e_source_authentication_set_user (ESourceAuthentication *extension,
829                                   const gchar *user)
830 {
831         g_return_if_fail (E_IS_SOURCE_AUTHENTICATION (extension));
832
833         g_mutex_lock (&extension->priv->property_lock);
834
835         if (g_strcmp0 (extension->priv->user, user) == 0) {
836                 g_mutex_unlock (&extension->priv->property_lock);
837                 return;
838         }
839
840         g_free (extension->priv->user);
841         extension->priv->user = e_util_strdup_strip (user);
842
843         g_mutex_unlock (&extension->priv->property_lock);
844
845         g_object_notify (G_OBJECT (extension), "user");
846 }