goa: Add missing linker flag (for real).
[platform/upstream/evolution-data-server.git] / libedataserver / e-source-webdav.c
1 /*
2  * e-source-webdav.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-webdav
21  * @include: libedataserver/libedataserver.h
22  * @short_description: #ESource extension for WebDAV settings
23  *
24  * The #ESourceWebdav extension tracks settings for accessing resources
25  * on a remote WebDAV server.
26  *
27  * This class exists in libedataserver because we have several
28  * WebDAV-based backends.  Each of these backends is free to use
29  * this class directly or subclass it with additional settings.
30  * Subclasses should override the extension name.
31  *
32  * The #SoupURI is parsed into components and distributed across
33  * several other built-in extensions such as #ESourceAuthentication
34  * and #ESourceSecurity.
35  *
36  * Access the extension as follows:
37  *
38  * |[
39  *   #include <libedataserver/libedataserver.h>
40  *
41  *   ESourceWebdav *extension;
42  *
43  *   extension = e_source_get_extension (source, E_SOURCE_EXTENSION_WEBDAV_BACKEND);
44  * ]|
45  **/
46
47 #ifdef HAVE_CONFIG_H
48 #include <config.h>
49 #endif
50
51 #include <glib/gi18n-lib.h>
52
53 #include <libedataserver/e-data-server-util.h>
54 #include <libedataserver/e-source-address-book.h>
55 #include <libedataserver/e-source-authentication.h>
56 #include <libedataserver/e-source-calendar.h>
57 #include <libedataserver/e-source-registry.h>
58 #include <libedataserver/e-source-security.h>
59
60 #include "e-source-webdav.h"
61
62 #define E_SOURCE_WEBDAV_GET_PRIVATE(obj) \
63         (G_TYPE_INSTANCE_GET_PRIVATE \
64         ((obj), E_TYPE_SOURCE_WEBDAV, ESourceWebdavPrivate))
65
66 struct _ESourceWebdavPrivate {
67         GMutex property_lock;
68         gchar *display_name;
69         gchar *email_address;
70         gchar *resource_path;
71         gchar *resource_query;
72         gchar *ssl_trust;
73         gboolean avoid_ifmatch;
74         gboolean calendar_auto_schedule;
75         gboolean ignore_invalid_cert;
76         SoupURI *soup_uri;
77 };
78
79 enum {
80         PROP_0,
81         PROP_AVOID_IFMATCH,
82         PROP_CALENDAR_AUTO_SCHEDULE,
83         PROP_DISPLAY_NAME,
84         PROP_EMAIL_ADDRESS,
85         PROP_IGNORE_INVALID_CERT,
86         PROP_RESOURCE_PATH,
87         PROP_RESOURCE_QUERY,
88         PROP_SOUP_URI,
89         PROP_SSL_TRUST
90 };
91
92 G_DEFINE_TYPE (
93         ESourceWebdav,
94         e_source_webdav,
95         E_TYPE_SOURCE_EXTENSION)
96
97 static void
98 source_webdav_notify_cb (GObject *object,
99                          GParamSpec *pspec,
100                          ESourceWebdav *extension)
101 {
102         g_object_notify (G_OBJECT (extension), "soup-uri");
103 }
104
105 static gboolean
106 source_webdav_user_to_method (GBinding *binding,
107                               const GValue *source_value,
108                               GValue *target_value,
109                               gpointer user_data)
110 {
111         const gchar *user;
112
113         user = g_value_get_string (source_value);
114         if (user == NULL || *user == '\0')
115                 g_value_set_string (target_value, "none");
116         else
117                 g_value_set_string (target_value, "plain/password");
118
119         return TRUE;
120 }
121
122 static void
123 source_webdav_update_properties_from_soup_uri (ESourceWebdav *webdav_extension)
124 {
125         ESource *source;
126         ESourceExtension *extension;
127         SoupURI *soup_uri;
128         const gchar *extension_name;
129
130         /* Do not use e_source_webdav_dup_soup_uri() here.  That
131          * builds the URI from properties we haven't yet updated. */
132         g_mutex_lock (&webdav_extension->priv->property_lock);
133         soup_uri = soup_uri_copy (webdav_extension->priv->soup_uri);
134         g_mutex_unlock (&webdav_extension->priv->property_lock);
135
136         extension = E_SOURCE_EXTENSION (webdav_extension);
137         source = e_source_extension_ref_source (extension);
138
139         g_object_set (
140                 extension,
141                 "resource-path", soup_uri->path,
142                 "resource-query", soup_uri->query,
143                 NULL);
144
145         extension_name = E_SOURCE_EXTENSION_AUTHENTICATION;
146         extension = e_source_get_extension (source, extension_name);
147
148         g_object_set (
149                 extension,
150                 "host", soup_uri->host,
151                 "port", soup_uri->port,
152                 "user", soup_uri->user,
153                 NULL);
154
155         extension_name = E_SOURCE_EXTENSION_SECURITY;
156         extension = e_source_get_extension (source, extension_name);
157
158         g_object_set (
159                 extension,
160                 "secure", (soup_uri->scheme == SOUP_URI_SCHEME_HTTPS),
161                 NULL);
162
163         g_object_unref (source);
164
165         soup_uri_free (soup_uri);
166 }
167
168 static void
169 source_webdav_update_soup_uri_from_properties (ESourceWebdav *webdav_extension)
170 {
171         ESource *source;
172         ESourceExtension *extension;
173         SoupURI *soup_uri;
174         const gchar *extension_name;
175         gchar *user;
176         gchar *host;
177         gchar *path;
178         gchar *query;
179         guint port;
180         gboolean secure;
181
182         extension = E_SOURCE_EXTENSION (webdav_extension);
183         source = e_source_extension_ref_source (extension);
184
185         g_object_get (
186                 extension,
187                 "resource-path", &path,
188                 "resource-query", &query,
189                 NULL);
190
191         extension_name = E_SOURCE_EXTENSION_AUTHENTICATION;
192         extension = e_source_get_extension (source, extension_name);
193
194         g_object_get (
195                 extension,
196                 "user", &user,
197                 "host", &host,
198                 "port", &port,
199                 NULL);
200
201         extension_name = E_SOURCE_EXTENSION_SECURITY;
202         extension = e_source_get_extension (source, extension_name);
203
204         g_object_get (
205                 extension,
206                 "secure", &secure,
207                 NULL);
208
209         g_object_unref (source);
210
211         g_mutex_lock (&webdav_extension->priv->property_lock);
212
213         soup_uri = webdav_extension->priv->soup_uri;
214
215         /* Try not to disturb the scheme, in case it's "webcal" or some
216          * other non-standard value.  But if we have to change it, do it. */
217         if (secure && soup_uri->scheme != SOUP_URI_SCHEME_HTTPS)
218                 soup_uri_set_scheme (soup_uri, SOUP_URI_SCHEME_HTTPS);
219         if (!secure && soup_uri->scheme == SOUP_URI_SCHEME_HTTPS)
220                 soup_uri_set_scheme (soup_uri, SOUP_URI_SCHEME_HTTP);
221
222         soup_uri_set_user (soup_uri, user);
223         soup_uri_set_host (soup_uri, host);
224         soup_uri_set_port (soup_uri, port);
225
226         /* SoupURI doesn't like NULL paths. */
227         soup_uri_set_path (soup_uri, (path != NULL) ? path : "");
228
229         soup_uri_set_query (soup_uri, query);
230
231         g_mutex_unlock (&webdav_extension->priv->property_lock);
232
233         g_free (user);
234         g_free (host);
235         g_free (path);
236         g_free (query);
237 }
238
239 static void
240 source_webdav_set_property (GObject *object,
241                             guint property_id,
242                             const GValue *value,
243                             GParamSpec *pspec)
244 {
245         switch (property_id) {
246                 case PROP_AVOID_IFMATCH:
247                         e_source_webdav_set_avoid_ifmatch (
248                                 E_SOURCE_WEBDAV (object),
249                                 g_value_get_boolean (value));
250                         return;
251
252                 case PROP_CALENDAR_AUTO_SCHEDULE:
253                         e_source_webdav_set_calendar_auto_schedule (
254                                 E_SOURCE_WEBDAV (object),
255                                 g_value_get_boolean (value));
256                         return;
257
258                 case PROP_DISPLAY_NAME:
259                         e_source_webdav_set_display_name (
260                                 E_SOURCE_WEBDAV (object),
261                                 g_value_get_string (value));
262                         return;
263
264                 case PROP_EMAIL_ADDRESS:
265                         e_source_webdav_set_email_address (
266                                 E_SOURCE_WEBDAV (object),
267                                 g_value_get_string (value));
268                         return;
269
270                 case PROP_IGNORE_INVALID_CERT:
271                         e_source_webdav_set_ignore_invalid_cert (
272                                 E_SOURCE_WEBDAV (object),
273                                 g_value_get_boolean (value));
274                         return;
275
276                 case PROP_RESOURCE_PATH:
277                         e_source_webdav_set_resource_path (
278                                 E_SOURCE_WEBDAV (object),
279                                 g_value_get_string (value));
280                         return;
281
282                 case PROP_RESOURCE_QUERY:
283                         e_source_webdav_set_resource_query (
284                                 E_SOURCE_WEBDAV (object),
285                                 g_value_get_string (value));
286                         return;
287
288                 case PROP_SOUP_URI:
289                         e_source_webdav_set_soup_uri (
290                                 E_SOURCE_WEBDAV (object),
291                                 g_value_get_boxed (value));
292                         return;
293
294                 case PROP_SSL_TRUST:
295                         e_source_webdav_set_ssl_trust (
296                                 E_SOURCE_WEBDAV (object),
297                                 g_value_get_string (value));
298                         return;
299         }
300
301         G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
302 }
303
304 static void
305 source_webdav_get_property (GObject *object,
306                             guint property_id,
307                             GValue *value,
308                             GParamSpec *pspec)
309 {
310         switch (property_id) {
311                 case PROP_AVOID_IFMATCH:
312                         g_value_set_boolean (
313                                 value,
314                                 e_source_webdav_get_avoid_ifmatch (
315                                 E_SOURCE_WEBDAV (object)));
316                         return;
317
318                 case PROP_CALENDAR_AUTO_SCHEDULE:
319                         g_value_set_boolean (
320                                 value,
321                                 e_source_webdav_get_calendar_auto_schedule (
322                                 E_SOURCE_WEBDAV (object)));
323                         return;
324
325                 case PROP_DISPLAY_NAME:
326                         g_value_take_string (
327                                 value,
328                                 e_source_webdav_dup_display_name (
329                                 E_SOURCE_WEBDAV (object)));
330                         return;
331
332                 case PROP_EMAIL_ADDRESS:
333                         g_value_take_string (
334                                 value,
335                                 e_source_webdav_dup_email_address (
336                                 E_SOURCE_WEBDAV (object)));
337                         return;
338
339                 case PROP_IGNORE_INVALID_CERT:
340                         g_value_set_boolean (
341                                 value,
342                                 e_source_webdav_get_ignore_invalid_cert (
343                                 E_SOURCE_WEBDAV (object)));
344                         return;
345
346                 case PROP_RESOURCE_PATH:
347                         g_value_take_string (
348                                 value,
349                                 e_source_webdav_dup_resource_path (
350                                 E_SOURCE_WEBDAV (object)));
351                         return;
352
353                 case PROP_RESOURCE_QUERY:
354                         g_value_take_string (
355                                 value,
356                                 e_source_webdav_dup_resource_query (
357                                 E_SOURCE_WEBDAV (object)));
358                         return;
359
360                 case PROP_SOUP_URI:
361                         g_value_take_boxed (
362                                 value,
363                                 e_source_webdav_dup_soup_uri (
364                                 E_SOURCE_WEBDAV (object)));
365                         return;
366
367                 case PROP_SSL_TRUST:
368                         g_value_take_string (
369                                 value,
370                                 e_source_webdav_dup_ssl_trust (
371                                 E_SOURCE_WEBDAV (object)));
372                         return;
373         }
374
375         G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
376 }
377
378 static void
379 source_webdav_finalize (GObject *object)
380 {
381         ESourceWebdavPrivate *priv;
382
383         priv = E_SOURCE_WEBDAV_GET_PRIVATE (object);
384
385         g_mutex_clear (&priv->property_lock);
386
387         g_free (priv->display_name);
388         g_free (priv->email_address);
389         g_free (priv->resource_path);
390         g_free (priv->resource_query);
391         g_free (priv->ssl_trust);
392
393         soup_uri_free (priv->soup_uri);
394
395         /* Chain up to parent's finalize() method. */
396         G_OBJECT_CLASS (e_source_webdav_parent_class)->finalize (object);
397 }
398
399 static void
400 source_webdav_constructed (GObject *object)
401 {
402         ESource *source;
403         ESourceExtension *extension;
404         const gchar *extension_name;
405
406         /* Chain up to parent's constructed() method. */
407         G_OBJECT_CLASS (e_source_webdav_parent_class)->constructed (object);
408
409         /* XXX I *think* we don't need to worry about disconnecting the
410          *     signals.  ESourceExtensions are only added, never removed,
411          *     and they all finalize with their ESource.  At least that's
412          *     how it's supposed to work if everyone follows the rules. */
413
414         extension = E_SOURCE_EXTENSION (object);
415         source = e_source_extension_ref_source (extension);
416
417         g_signal_connect (
418                 extension, "notify::resource-path",
419                 G_CALLBACK (source_webdav_notify_cb), object);
420
421         g_signal_connect (
422                 extension, "notify::resource-query",
423                 G_CALLBACK (source_webdav_notify_cb), object);
424
425         extension_name = E_SOURCE_EXTENSION_AUTHENTICATION;
426         extension = e_source_get_extension (source, extension_name);
427
428         g_signal_connect (
429                 extension, "notify::host",
430                 G_CALLBACK (source_webdav_notify_cb), object);
431
432         g_signal_connect (
433                 extension, "notify::port",
434                 G_CALLBACK (source_webdav_notify_cb), object);
435
436         g_signal_connect (
437                 extension, "notify::user",
438                 G_CALLBACK (source_webdav_notify_cb), object);
439
440         /* This updates the authentication method
441          * based on whether a user name was given. */
442         g_object_bind_property_full (
443                 extension, "user",
444                 extension, "method",
445                 G_BINDING_SYNC_CREATE,
446                 source_webdav_user_to_method,
447                 NULL,
448                 NULL, (GDestroyNotify) NULL);
449
450         extension_name = E_SOURCE_EXTENSION_SECURITY;
451         extension = e_source_get_extension (source, extension_name);
452
453         g_signal_connect (
454                 extension, "notify::secure",
455                 G_CALLBACK (source_webdav_notify_cb), object);
456
457         g_object_unref (source);
458 }
459
460 static void
461 e_source_webdav_class_init (ESourceWebdavClass *class)
462 {
463         GObjectClass *object_class;
464         ESourceExtensionClass *extension_class;
465
466         g_type_class_add_private (class, sizeof (ESourceWebdavPrivate));
467
468         object_class = G_OBJECT_CLASS (class);
469         object_class->set_property = source_webdav_set_property;
470         object_class->get_property = source_webdav_get_property;
471         object_class->finalize = source_webdav_finalize;
472         object_class->constructed = source_webdav_constructed;
473
474         extension_class = E_SOURCE_EXTENSION_CLASS (class);
475         extension_class->name = E_SOURCE_EXTENSION_WEBDAV_BACKEND;
476
477         g_object_class_install_property (
478                 object_class,
479                 PROP_AVOID_IFMATCH,
480                 g_param_spec_boolean (
481                         "avoid-ifmatch",
482                         "Avoid If-Match",
483                         "Work around a bug in old Apache servers",
484                         FALSE,
485                         G_PARAM_READWRITE |
486                         G_PARAM_CONSTRUCT |
487                         E_SOURCE_PARAM_SETTING));
488
489         g_object_class_install_property (
490                 object_class,
491                 PROP_CALENDAR_AUTO_SCHEDULE,
492                 g_param_spec_boolean (
493                         "calendar-auto-schedule",
494                         "Calendar Auto-Schedule",
495                         "Whether the server handles meeting "
496                         "invitations (CalDAV-only)",
497                         FALSE,
498                         G_PARAM_READWRITE |
499                         G_PARAM_CONSTRUCT |
500                         E_SOURCE_PARAM_SETTING));
501
502         g_object_class_install_property (
503                 object_class,
504                 PROP_DISPLAY_NAME,
505                 g_param_spec_string (
506                         "display-name",
507                         "Display Name",
508                         "Display name of the WebDAV resource",
509                         "",
510                         G_PARAM_READWRITE |
511                         G_PARAM_CONSTRUCT |
512                         E_SOURCE_PARAM_SETTING));
513
514         g_object_class_install_property (
515                 object_class,
516                 PROP_EMAIL_ADDRESS,
517                 g_param_spec_string (
518                         "email-address",
519                         "Email Address",
520                         "The user's email address",
521                         "",
522                         G_PARAM_READWRITE |
523                         G_PARAM_CONSTRUCT |
524                         E_SOURCE_PARAM_SETTING));
525
526         g_object_class_install_property (
527                 object_class,
528                 PROP_IGNORE_INVALID_CERT,
529                 g_param_spec_boolean (
530                         "ignore-invalid-cert",
531                         "Ignore Invalid Cert",
532                         "Ignore invalid SSL certificates",
533                         FALSE,
534                         G_PARAM_READWRITE |
535                         G_PARAM_CONSTRUCT |
536                         E_SOURCE_PARAM_SETTING));
537
538         g_object_class_install_property (
539                 object_class,
540                 PROP_RESOURCE_PATH,
541                 g_param_spec_string (
542                         "resource-path",
543                         "Resource Path",
544                         "Absolute path to a WebDAV resource",
545                         NULL,
546                         G_PARAM_READWRITE |
547                         G_PARAM_CONSTRUCT |
548                         E_SOURCE_PARAM_SETTING));
549
550         g_object_class_install_property (
551                 object_class,
552                 PROP_RESOURCE_QUERY,
553                 g_param_spec_string (
554                         "resource-query",
555                         "Resource Query",
556                         "Query to access a WebDAV resource",
557                         NULL,
558                         G_PARAM_READWRITE |
559                         G_PARAM_CONSTRUCT |
560                         E_SOURCE_PARAM_SETTING));
561
562         g_object_class_install_property (
563                 object_class,
564                 PROP_SOUP_URI,
565                 g_param_spec_boxed (
566                         "soup-uri",
567                         "SoupURI",
568                         "WebDAV service as a SoupURI",
569                         SOUP_TYPE_URI,
570                         G_PARAM_READWRITE));
571
572         g_object_class_install_property (
573                 object_class,
574                 PROP_SSL_TRUST,
575                 g_param_spec_string (
576                         "ssl-trust",
577                         "SSL Trust",
578                         "SSL certificate trust setting, "
579                         "for invalid server certificates",
580                         NULL,
581                         G_PARAM_READWRITE |
582                         G_PARAM_CONSTRUCT |
583                         E_SOURCE_PARAM_SETTING));
584 }
585
586 static void
587 e_source_webdav_init (ESourceWebdav *extension)
588 {
589         extension->priv = E_SOURCE_WEBDAV_GET_PRIVATE (extension);
590         g_mutex_init (&extension->priv->property_lock);
591
592         /* Initialize this enough for SOUP_URI_IS_VALID() to pass. */
593         extension->priv->soup_uri = soup_uri_new (NULL);
594         extension->priv->soup_uri->scheme = SOUP_URI_SCHEME_HTTP;
595         extension->priv->soup_uri->path = g_strdup ("");
596 }
597
598 /**
599  * e_source_webdav_get_avoid_ifmatch:
600  * @extension: an #ESourceWebdav
601  *
602  * This setting works around a
603  * <ulink url="https://issues.apache.org/bugzilla/show_bug.cgi?id=38034">
604  * bug</ulink> in older Apache mod_dav versions.
605  *
606  * <note>
607  *   <para>
608  *     We may deprecate this once Apache 2.2.8 or newer becomes
609  *     sufficiently ubiquitous, or we figure out a way to detect
610  *     and work around the bug automatically.
611  *   </para>
612  * </note>
613  *
614  * Returns: whether the WebDAV server is known to exhibit the bug
615  *
616  * Since: 3.6
617  **/
618 gboolean
619 e_source_webdav_get_avoid_ifmatch (ESourceWebdav *extension)
620 {
621         g_return_val_if_fail (E_IS_SOURCE_WEBDAV (extension), FALSE);
622
623         return extension->priv->avoid_ifmatch;
624 }
625
626 /**
627  * e_source_webdav_set_avoid_ifmatch:
628  * @extension: an #ESourceWebdav
629  * @avoid_ifmatch: whether the WebDAV server is known to exhibit the bug
630  *
631  * This setting works around a
632  * <ulink url="https://issues.apache.org/bugzilla/show_bug.cgi?id=38034">
633  * bug</ulink> in older Apache mod_dav versions.
634  *
635  * <note>
636  *   <para>
637  *     We may deprecate this once Apache 2.2.8 or newer becomes
638  *     sufficiently ubiquitous, or we figure out a way to detect
639  *     and work around the bug automatically.
640  *   </para>
641  * </note>
642  *
643  * Since: 3.6
644  **/
645 void
646 e_source_webdav_set_avoid_ifmatch (ESourceWebdav *extension,
647                                    gboolean avoid_ifmatch)
648 {
649         g_return_if_fail (E_IS_SOURCE_WEBDAV (extension));
650
651         if (extension->priv->avoid_ifmatch == avoid_ifmatch)
652                 return;
653
654         extension->priv->avoid_ifmatch = avoid_ifmatch;
655
656         g_object_notify (G_OBJECT (extension), "avoid-ifmatch");
657 }
658
659 /**
660  * e_source_webdav_get_calendar_auto_schedule:
661  * @extension: an #ESourceWebdav
662  *
663  * FIXME Document me!
664  *
665  * Since: 3.6
666  **/
667 gboolean
668 e_source_webdav_get_calendar_auto_schedule (ESourceWebdav *extension)
669 {
670         g_return_val_if_fail (E_IS_SOURCE_WEBDAV (extension), FALSE);
671
672         return extension->priv->calendar_auto_schedule;
673 }
674
675 /**
676  * e_source_webdav_set_calendar_auto_schedule:
677  * @extension: an #ESourceWebdav
678  * @calendar_auto_schedule: whether the server supports the
679  * "calendar-auto-schedule" feature of CalDAV
680  *
681  * FIXME Document me!
682  *
683  * Since: 3.6
684  **/
685 void
686 e_source_webdav_set_calendar_auto_schedule (ESourceWebdav *extension,
687                                             gboolean calendar_auto_schedule)
688 {
689         g_return_if_fail (E_IS_SOURCE_WEBDAV (extension));
690
691         if (extension->priv->calendar_auto_schedule == calendar_auto_schedule)
692                 return;
693
694         extension->priv->calendar_auto_schedule = calendar_auto_schedule;
695
696         g_object_notify (G_OBJECT (extension), "calendar-auto-schedule");
697 }
698
699 /**
700  * e_source_webdav_get_display_name:
701  * @extension: an #ESourceWebdav
702  *
703  * Returns the last known display name of a WebDAV resource, which may
704  * differ from the #ESource:display-name property of the #ESource to which
705  * @extension belongs.
706  *
707  * Returns: the display name of the WebDAV resource
708  *
709  * Since: 3.6
710  **/
711 const gchar *
712 e_source_webdav_get_display_name (ESourceWebdav *extension)
713 {
714         g_return_val_if_fail (E_IS_SOURCE_WEBDAV (extension), NULL);
715
716         return extension->priv->display_name;
717 }
718
719 /**
720  * e_source_webdav_dup_display_name:
721  * @extension: an #ESourceWebdav
722  *
723  * Thread-safe variation of e_source_webdav_get_display_name().
724  * Use this function when accessing @extension from multiple threads.
725  *
726  * The returned string should be freed with g_free() when no longer needed.
727  *
728  * Returns: a newly-allocated copy of #ESourceWebdav:display-name
729  *
730  * Since: 3.6
731  **/
732 gchar *
733 e_source_webdav_dup_display_name (ESourceWebdav *extension)
734 {
735         const gchar *protected;
736         gchar *duplicate;
737
738         g_return_val_if_fail (E_IS_SOURCE_WEBDAV (extension), NULL);
739
740         g_mutex_lock (&extension->priv->property_lock);
741
742         protected = e_source_webdav_get_display_name (extension);
743         duplicate = g_strdup (protected);
744
745         g_mutex_unlock (&extension->priv->property_lock);
746
747         return duplicate;
748 }
749
750 /**
751  * e_source_webdav_set_display_name:
752  * @extension: an #ESourceWebdav
753  * @display_name: (allow-none): the display name of the WebDAV resource,
754  *                or %NULL
755  *
756  * Updates the last known display name of a WebDAV resource, which may
757  * differ from the #ESource:display-name property of the #ESource to which
758  * @extension belongs.
759  *
760  * The internal copy of @display_name is automatically stripped of leading
761  * and trailing whitespace.  If the resulting string is empty, %NULL is set
762  * instead.
763  *
764  * Since: 3.6
765  **/
766 void
767 e_source_webdav_set_display_name (ESourceWebdav *extension,
768                                   const gchar *display_name)
769 {
770         g_return_if_fail (E_IS_SOURCE_WEBDAV (extension));
771
772         g_mutex_lock (&extension->priv->property_lock);
773
774         if (g_strcmp0 (extension->priv->display_name, display_name) == 0) {
775                 g_mutex_unlock (&extension->priv->property_lock);
776                 return;
777         }
778
779         g_free (extension->priv->display_name);
780         extension->priv->display_name = e_util_strdup_strip (display_name);
781
782         g_mutex_unlock (&extension->priv->property_lock);
783
784         g_object_notify (G_OBJECT (extension), "display-name");
785 }
786
787 /**
788  * e_source_webdav_get_email_address:
789  * @extension: an #ESourceWebdav
790  *
791  * Returns the user's email address which can be passed to a CalDAV server
792  * if the user wishes to receive scheduling messages.
793  *
794  * Returns: the user's email address
795  *
796  * Since: 3.6
797  **/
798 const gchar *
799 e_source_webdav_get_email_address (ESourceWebdav *extension)
800 {
801         g_return_val_if_fail (E_IS_SOURCE_WEBDAV (extension), NULL);
802
803         return extension->priv->email_address;
804 }
805
806 /**
807  * e_source_webdav_dup_email_address:
808  * @extension: an #ESourceWebdav
809  *
810  * Thread-safe variation of e_source_webdav_get_email_address().
811  * Use this function when accessing @extension from multiple threads.
812  *
813  * The returned string should be freed with g_free() when no longer needed.
814  *
815  * Returns: the newly-allocated copy of #ESourceWebdav:email-address
816  *
817  * Since: 3.6
818  **/
819 gchar *
820 e_source_webdav_dup_email_address (ESourceWebdav *extension)
821 {
822         const gchar *protected;
823         gchar *duplicate;
824
825         g_return_val_if_fail (E_IS_SOURCE_WEBDAV (extension), NULL);
826
827         g_mutex_lock (&extension->priv->property_lock);
828
829         protected = e_source_webdav_get_email_address (extension);
830         duplicate = g_strdup (protected);
831
832         g_mutex_unlock (&extension->priv->property_lock);
833
834         return duplicate;
835 }
836
837 /**
838  * e_source_webdav_set_email_address:
839  * @extension: an #ESourceWebdav
840  * @email_address: (allow-none): the user's email address, or %NULL
841  *
842  * Sets the user's email address which can be passed to a CalDAV server if
843  * the user wishes to receive scheduling messages.
844  *
845  * The internal copy of @email_address is automatically stripped of leading
846  * and trailing whitespace.  If the resulting string is empty, %NULL is set
847  * instead.
848  *
849  * Since: 3.6
850  **/
851 void
852 e_source_webdav_set_email_address (ESourceWebdav *extension,
853                                    const gchar *email_address)
854 {
855         g_return_if_fail (E_IS_SOURCE_WEBDAV (extension));
856
857         g_mutex_lock (&extension->priv->property_lock);
858
859         if (g_strcmp0 (extension->priv->email_address, email_address) == 0) {
860                 g_mutex_unlock (&extension->priv->property_lock);
861                 return;
862         }
863
864         g_free (extension->priv->email_address);
865         extension->priv->email_address = e_util_strdup_strip (email_address);
866
867         g_mutex_unlock (&extension->priv->property_lock);
868
869         g_object_notify (G_OBJECT (extension), "email-address");
870 }
871
872 /**
873  * e_source_webdav_get_ignore_invalid_cert:
874  * @extension: an #ESourceWebdav
875  *
876  * Returns %TRUE if invalid SSL certificates should be ignored.
877  *
878  * This option allows SSL certificates to be accepted even if they have
879  * signed by an unrecognized Certificate Authority.
880  *
881  * Returns: whether invalid SSL certificates should be ignored
882  *
883  * Since: 3.6
884  *
885  * Deprecated: 3.8: The trust prompt APIs replace this.
886  **/
887 gboolean
888 e_source_webdav_get_ignore_invalid_cert (ESourceWebdav *extension)
889 {
890         g_return_val_if_fail (E_IS_SOURCE_WEBDAV (extension), FALSE);
891
892         return extension->priv->ignore_invalid_cert;
893 }
894
895 /**
896  * e_source_webdav_set_ignore_invalid_cert:
897  * @extension: an #ESourceWebdav
898  * @ignore_invalid_cert: whether invalid SSL certificates should be ignored
899  *
900  * Sets whether invalid SSL certificates should be ignored.
901  *
902  * This option allows SSL certificates to be accepted even if they have
903  * signed by an unrecognized Certificate Authority.
904  *
905  * Since: 3.6
906  *
907  * Deprecated: 3.8: The trust prompt APIs replace this.
908  **/
909 void
910 e_source_webdav_set_ignore_invalid_cert (ESourceWebdav *extension,
911                                          gboolean ignore_invalid_cert)
912 {
913         g_return_if_fail (E_IS_SOURCE_WEBDAV (extension));
914
915         if (extension->priv->ignore_invalid_cert == ignore_invalid_cert)
916                 return;
917
918         extension->priv->ignore_invalid_cert = ignore_invalid_cert;
919
920         g_object_notify (G_OBJECT (extension), "ignore-invalid-cert");
921 }
922
923 /**
924  * e_source_webdav_get_resource_path:
925  * @extension: an #ESourceWebdav
926  *
927  * Returns the absolute path to a resource on a WebDAV server.
928  *
929  * Returns: the absolute path to a WebDAV resource
930  *
931  * Since: 3.6
932  **/
933 const gchar *
934 e_source_webdav_get_resource_path (ESourceWebdav *extension)
935 {
936         g_return_val_if_fail (E_IS_SOURCE_WEBDAV (extension), NULL);
937
938         return extension->priv->resource_path;
939 }
940
941 /**
942  * e_source_webdav_dup_resource_path:
943  * @extension: an #ESourceWebdav
944  *
945  * Thread-safe variation of e_source_webdav_get_resource_path().
946  * Use this function when accessing @extension from multiple threads.
947  *
948  * The returned string should be freed with g_free() when no longer needed.
949  *
950  * Returns: the newly-allocated copy of #ESourceWebdav:resource-path
951  *
952  * Since: 3.6
953  **/
954 gchar *
955 e_source_webdav_dup_resource_path (ESourceWebdav *extension)
956 {
957         const gchar *protected;
958         gchar *duplicate;
959
960         g_return_val_if_fail (E_IS_SOURCE_WEBDAV (extension), NULL);
961
962         g_mutex_lock (&extension->priv->property_lock);
963
964         protected = e_source_webdav_get_resource_path (extension);
965         duplicate = g_strdup (protected);
966
967         g_mutex_unlock (&extension->priv->property_lock);
968
969         return duplicate;
970 }
971
972 /**
973  * e_source_webdav_set_resource_path:
974  * @extension: an #ESourceWebdav
975  * @resource_path: (allow-none): the absolute path to a WebDAV resource,
976  *                 or %NULL
977  *
978  * Sets the absolute path to a resource on a WebDAV server.
979  *
980  * The internal copy of @resource_path is automatically stripped of leading
981  * and trailing whitespace.  If the resulting string is empty, %NULL is set
982  * instead.
983  *
984  * Since: 3.6
985  **/
986 void
987 e_source_webdav_set_resource_path (ESourceWebdav *extension,
988                                    const gchar *resource_path)
989 {
990         g_return_if_fail (E_IS_SOURCE_WEBDAV (extension));
991
992         g_mutex_lock (&extension->priv->property_lock);
993
994         if (g_strcmp0 (extension->priv->resource_path, resource_path) == 0) {
995                 g_mutex_unlock (&extension->priv->property_lock);
996                 return;
997         }
998
999         g_free (extension->priv->resource_path);
1000         extension->priv->resource_path = e_util_strdup_strip (resource_path);
1001
1002         g_mutex_unlock (&extension->priv->property_lock);
1003
1004         g_object_notify (G_OBJECT (extension), "resource-path");
1005 }
1006
1007 /**
1008  * e_source_webdav_get_resource_query:
1009  * @extension: an #ESourceWebdav
1010  *
1011  * Returns the URI query required to access a resource on a WebDAV server.
1012  *
1013  * This is typically used when the #ESourceWebdav:resource-path points not
1014  * to the resource itself but to a web program that generates the resource
1015  * content on-the-fly.  The #ESourceWebdav:resource-query holds the input
1016  * values for the program.
1017  *
1018  * Returns: the query to access a WebDAV resource
1019  *
1020  * Since: 3.6
1021  **/
1022 const gchar *
1023 e_source_webdav_get_resource_query (ESourceWebdav *extension)
1024 {
1025         g_return_val_if_fail (E_IS_SOURCE_WEBDAV (extension), NULL);
1026
1027         return extension->priv->resource_query;
1028 }
1029
1030 /**
1031  * e_source_webdav_dup_resource_query:
1032  * @extension: an #ESourceWebdav
1033  *
1034  * Thread-safe variation of e_source_webdav_get_resource_query().
1035  * Use this function when accessing @extension from multiple threads.
1036  *
1037  * The returned string should be freed with g_free() when no longer needed.
1038  *
1039  * Returns: the newly-allocated copy of #ESourceWebdav:resource-query
1040  *
1041  * Since: 3.6
1042  **/
1043 gchar *
1044 e_source_webdav_dup_resource_query (ESourceWebdav *extension)
1045 {
1046         const gchar *protected;
1047         gchar *duplicate;
1048
1049         g_return_val_if_fail (E_IS_SOURCE_WEBDAV (extension), NULL);
1050
1051         g_mutex_lock (&extension->priv->property_lock);
1052
1053         protected = e_source_webdav_get_resource_query (extension);
1054         duplicate = g_strdup (protected);
1055
1056         g_mutex_unlock (&extension->priv->property_lock);
1057
1058         return duplicate;
1059 }
1060
1061 /**
1062  * e_source_webdav_set_resource_query:
1063  * @extension: an #ESourceWebdav
1064  * @resource_query: (allow-none): the query to access a WebDAV resource,
1065  *                  or %NULL
1066  *
1067  * Sets the URI query required to access a resource on a WebDAV server.
1068  *
1069  * This is typically used when the #ESourceWebdav:resource-path points not
1070  * to the resource itself but to a web program that generates the resource
1071  * content on-the-fly.  The #ESourceWebdav:resource-query holds the input
1072  * values for the program.
1073  *
1074  * The internal copy of @resource_query is automatically stripped of leading
1075  * and trailing whitespace.  If the resulting string is empty, %NULL is set
1076  * instead.
1077  *
1078  * Since: 3.6
1079  **/
1080 void
1081 e_source_webdav_set_resource_query (ESourceWebdav *extension,
1082                                     const gchar *resource_query)
1083 {
1084         g_return_if_fail (E_IS_SOURCE_WEBDAV (extension));
1085
1086         g_mutex_lock (&extension->priv->property_lock);
1087
1088         if (g_strcmp0 (extension->priv->resource_query, resource_query) == 0) {
1089                 g_mutex_unlock (&extension->priv->property_lock);
1090                 return;
1091         }
1092
1093         g_free (extension->priv->resource_query);
1094         extension->priv->resource_query = e_util_strdup_strip (resource_query);
1095
1096         g_mutex_unlock (&extension->priv->property_lock);
1097
1098         g_object_notify (G_OBJECT (extension), "resource-query");
1099 }
1100
1101 /**
1102  * e_source_webdav_get_ssl_trust:
1103  * @extension: an #ESourceWebdav
1104  *
1105  * Returns an SSL certificate trust for the @extension.
1106  * The value encodes three parameters, divided by a pipe '|',
1107  * the first is users preference, can be one of "reject", "accept",
1108  * "temporary-reject" and "temporary-accept". The second is a host
1109  * name for which the trust was set. Finally the last is a SHA1
1110  * hash of the certificate. This is not meant to be changed by a caller,
1111  * it is supposed to be manipulated with e_source_webdav_prepare_ssl_trust_prompt()
1112  * and e_source_webdav_store_ssl_trust_prompt().
1113  *
1114  * Returns: an SSL certificate trust for the @extension
1115  *
1116  * Since: 3.8
1117  **/
1118 const gchar *
1119 e_source_webdav_get_ssl_trust (ESourceWebdav *extension)
1120 {
1121         g_return_val_if_fail (E_IS_SOURCE_WEBDAV (extension), NULL);
1122
1123         return extension->priv->ssl_trust;
1124 }
1125
1126 /**
1127  * e_source_webdav_dup_ssl_trust:
1128  * @extension: an #ESourceWebdav
1129  *
1130  * Thread-safe variation of e_source_webdav_get_ssl_trust().
1131  * Use this function when accessing @extension from multiple threads.
1132  *
1133  * The returned string should be freed with g_free() when no longer needed.
1134  *
1135  * Returns: the newly-allocated copy of #ESourceWebdav:ssl-trust
1136  *
1137  * Since: 3.8
1138  **/
1139 gchar *
1140 e_source_webdav_dup_ssl_trust (ESourceWebdav *extension)
1141 {
1142         const gchar *protected;
1143         gchar *duplicate;
1144
1145         g_return_val_if_fail (E_IS_SOURCE_WEBDAV (extension), NULL);
1146
1147         g_mutex_lock (&extension->priv->property_lock);
1148
1149         protected = e_source_webdav_get_ssl_trust (extension);
1150         duplicate = g_strdup (protected);
1151
1152         g_mutex_unlock (&extension->priv->property_lock);
1153
1154         return duplicate;
1155 }
1156
1157 /**
1158  * e_source_webdav_set_ssl_trust:
1159  * @extension: an #ESourceWebdav
1160  * @ssl_trust: (allow-none): the ssl_trust to store, or %NULL to unset
1161  *
1162  * Sets the SSL certificate trust. See e_source_webdav_get_ssl_trust()
1163  * for more infomation about its content and how to use it.
1164  *
1165  * Since: 3.8
1166  **/
1167 void
1168 e_source_webdav_set_ssl_trust (ESourceWebdav *extension,
1169                                const gchar *ssl_trust)
1170 {
1171         g_return_if_fail (E_IS_SOURCE_WEBDAV (extension));
1172
1173         g_mutex_lock (&extension->priv->property_lock);
1174
1175         if (g_strcmp0 (extension->priv->ssl_trust, ssl_trust) == 0) {
1176                 g_mutex_unlock (&extension->priv->property_lock);
1177                 return;
1178         }
1179
1180         g_free (extension->priv->ssl_trust);
1181         extension->priv->ssl_trust = g_strdup (ssl_trust);
1182
1183         g_mutex_unlock (&extension->priv->property_lock);
1184
1185         g_object_notify (G_OBJECT (extension), "ssl-trust");
1186 }
1187
1188 /**
1189  * e_source_webdav_dup_soup_uri:
1190  * @extension: an #ESourceWebdav
1191  *
1192  * This is a convenience function which returns a newly-allocated
1193  * #SoupURI, its contents assembled from the #ESourceAuthentication
1194  * extension, the #ESourceSecurity extension, and @extension itself.
1195  * Free the returned #SoupURI with soup_uri_free().
1196  *
1197  * Returns: (transfer full): a newly-allocated #SoupURI
1198  *
1199  * Since: 3.6
1200  **/
1201 SoupURI *
1202 e_source_webdav_dup_soup_uri (ESourceWebdav *extension)
1203 {
1204         SoupURI *duplicate;
1205
1206         g_return_val_if_fail (E_IS_SOURCE_WEBDAV (extension), NULL);
1207
1208         /* Keep this outside of the property lock. */
1209         source_webdav_update_soup_uri_from_properties (extension);
1210
1211         g_mutex_lock (&extension->priv->property_lock);
1212
1213         duplicate = soup_uri_copy (extension->priv->soup_uri);
1214
1215         g_mutex_unlock (&extension->priv->property_lock);
1216
1217         return duplicate;
1218 }
1219
1220 /**
1221  * e_source_webdav_set_soup_uri:
1222  * @extension: an #ESourceWebdav
1223  * @soup_uri: a #SoupURI
1224  *
1225  * This is a convenience function which propagates the components of
1226  * @uri to the #ESourceAuthentication extension, the #ESourceSecurity
1227  * extension, and @extension itself.  (The "fragment" component of
1228  * @uri is ignored.)
1229  *
1230  * Since: 3.6
1231  **/
1232 void
1233 e_source_webdav_set_soup_uri (ESourceWebdav *extension,
1234                               SoupURI *soup_uri)
1235 {
1236         g_return_if_fail (E_IS_SOURCE_WEBDAV (extension));
1237         g_return_if_fail (SOUP_URI_IS_VALID (soup_uri));
1238
1239         g_mutex_lock (&extension->priv->property_lock);
1240
1241         /* Do not test for URI equality because our
1242          * internal SoupURI might not be up-to-date. */
1243
1244         soup_uri_free (extension->priv->soup_uri);
1245         extension->priv->soup_uri = soup_uri_copy (soup_uri);
1246
1247         g_mutex_unlock (&extension->priv->property_lock);
1248
1249         g_object_freeze_notify (G_OBJECT (extension));
1250         source_webdav_update_properties_from_soup_uri (extension);
1251         g_object_notify (G_OBJECT (extension), "soup-uri");
1252         g_object_thaw_notify (G_OBJECT (extension));
1253 }
1254
1255 static gboolean
1256 decode_ssl_trust (ESourceWebdav *extension,
1257                   ETrustPromptResponse *response,
1258                   gchar **host,
1259                   gchar **hash)
1260 {
1261         gchar *ssl_trust, **strv;
1262
1263         g_return_val_if_fail (E_IS_SOURCE_WEBDAV (extension), FALSE);
1264
1265         ssl_trust = e_source_webdav_dup_ssl_trust (extension);
1266         if (!ssl_trust || !*ssl_trust) {
1267                 g_free (ssl_trust);
1268                 return FALSE;
1269         }
1270
1271         strv = g_strsplit (ssl_trust, "|", 3);
1272         if (!strv || !strv[0] || !strv[1] || !strv[2] || strv[3]) {
1273                 g_free (ssl_trust);
1274                 g_strfreev (strv);
1275                 return FALSE;
1276         }
1277
1278         if (response) {
1279                 const gchar *resp = strv[0];
1280
1281                 if (g_strcmp0 (resp, "reject") == 0)
1282                         *response = E_TRUST_PROMPT_RESPONSE_REJECT;
1283                 else if (g_strcmp0 (resp, "accept") == 0)
1284                         *response = E_TRUST_PROMPT_RESPONSE_ACCEPT;
1285                 else if (g_strcmp0 (resp, "temporary-reject") == 0)
1286                         *response = E_TRUST_PROMPT_RESPONSE_REJECT_TEMPORARILY;
1287                 else if (g_strcmp0 (resp, "temporary-accept") == 0)
1288                         *response = E_TRUST_PROMPT_RESPONSE_ACCEPT_TEMPORARILY;
1289                 else
1290                         *response = E_TRUST_PROMPT_RESPONSE_UNKNOWN;
1291         }
1292
1293         if (host)
1294                 *host = g_strdup (strv[1]);
1295
1296         if (hash)
1297                 *hash = g_strdup (strv[2]);
1298
1299         g_free (ssl_trust);
1300         g_strfreev (strv);
1301
1302         return TRUE;
1303 }
1304
1305 static gboolean
1306 encode_ssl_trust (ESourceWebdav *extension,
1307                   ETrustPromptResponse response,
1308                   const gchar *host,
1309                   const gchar *hash)
1310 {
1311         gchar *ssl_trust;
1312         const gchar *resp;
1313         gboolean changed;
1314
1315         g_return_val_if_fail (E_IS_SOURCE_WEBDAV (extension), FALSE);
1316
1317         if (response == E_TRUST_PROMPT_RESPONSE_REJECT)
1318                 resp = "reject";
1319         else if (response == E_TRUST_PROMPT_RESPONSE_ACCEPT)
1320                 resp = "accept";
1321         else if (response == E_TRUST_PROMPT_RESPONSE_REJECT_TEMPORARILY)
1322                 resp = "temporary-reject";
1323         else if (response == E_TRUST_PROMPT_RESPONSE_ACCEPT_TEMPORARILY)
1324                 resp = "temporary-accept";
1325         else
1326                 resp = "temporary-reject";
1327
1328         if (host && *host && hash && *hash) {
1329                 ssl_trust = g_strconcat (resp, "|", host, "|", hash, NULL);
1330         } else {
1331                 ssl_trust = NULL;
1332         }
1333
1334         changed = g_strcmp0 (extension->priv->ssl_trust, ssl_trust) != 0;
1335
1336         if (changed)
1337                 e_source_webdav_set_ssl_trust (extension, ssl_trust);
1338
1339         g_free (ssl_trust);
1340
1341         return changed;
1342 }
1343
1344 /**
1345  * e_source_webdav_prepare_ssl_trust_prompt:
1346  * @extension: an #ESourceWebdav
1347  * @message: a #SoupMessage with #SOUP_STATUS_SSL_FAILED status code
1348  * @registry: an #ESourceRegistry, to use for parent lookups
1349  * @parameters: an #ENamedParameters to be populated
1350  *
1351  * Checks @messages<!-- -->'s certificate against currently stored trust
1352  * response and either returns what to do immediately, or returns
1353  * #E_TRUST_PROMPT_RESPONSE_UNKNOWN and populates @parameters with necessary
1354  * values for a trust prompt.
1355  *
1356  * Returns: What to do with SSL connection, where
1357  *          #E_TRUST_PROMPT_RESPONSE_UNKNOWN means 'ask a user, with
1358  *          populated parameters'.
1359  *
1360  * Note: The #E_TRUST_PROMPT_RESPONSE_REJECT is returned on any errors, like
1361  *  the @message not being with the #SOUP_STATUS_SSL_FAILED status code,
1362  *  no certificate being stored in the @message and so on.
1363  *
1364  * Since: 3.8
1365  **/
1366 ETrustPromptResponse
1367 e_source_webdav_prepare_ssl_trust_prompt (ESourceWebdav *extension,
1368                                           SoupMessage *message,
1369                                           ESourceRegistry *registry,
1370                                           ENamedParameters *parameters)
1371 {
1372         ESource *source, *parent_source = NULL;
1373         ETrustPromptResponse res;
1374
1375         g_return_val_if_fail (
1376                 E_IS_SOURCE_WEBDAV (extension),
1377                 E_TRUST_PROMPT_RESPONSE_REJECT);
1378         g_return_val_if_fail (
1379                 SOUP_IS_MESSAGE (message),
1380                 E_TRUST_PROMPT_RESPONSE_REJECT);
1381         g_return_val_if_fail (
1382                 E_IS_SOURCE_REGISTRY (registry),
1383                 E_TRUST_PROMPT_RESPONSE_REJECT);
1384         g_return_val_if_fail (
1385                 parameters != NULL,
1386                 E_TRUST_PROMPT_RESPONSE_REJECT);
1387
1388         source = e_source_extension_ref_source (E_SOURCE_EXTENSION (extension));
1389         if (source != NULL) {
1390                 const gchar *parent_uid;
1391
1392                 parent_uid = e_source_get_parent (source);
1393
1394                 if (parent_uid != NULL)
1395                         parent_source = e_source_registry_ref_source (
1396                                 registry, parent_uid);
1397
1398                 g_object_unref (source);
1399         }
1400
1401         res = e_source_webdav_prepare_ssl_trust_prompt_with_parent (
1402                 extension, message, parent_source, parameters);
1403
1404         if (parent_source)
1405                 g_object_unref (parent_source);
1406
1407         return res;
1408 }
1409
1410 /**
1411  * e_source_webdav_prepare_ssl_trust_prompt_with_parent:
1412  * @extension: an #ESourceWebdav
1413  * @message: a #SoupMessage with #SOUP_STATUS_SSL_FAILED status code
1414  * @parent_source: an #ESource, parent of the @extension<!-- -->'s source
1415  * @parameters: an #ENamedParameters to be populated
1416  *
1417  * The same as e_source_webdav_prepare_ssl_trust_prompt(), only takes
1418  * @parent_source directly, instead of an #ESourceRegistry.
1419  *
1420  * See e_source_webdav_prepare_ssl_trust_prompt() for more details.
1421  *
1422  * Since: 3.8
1423  **/
1424 ETrustPromptResponse
1425 e_source_webdav_prepare_ssl_trust_prompt_with_parent (ESourceWebdav *extension,
1426                                                       SoupMessage *message,
1427                                                       ESource *parent_source,
1428                                                       ENamedParameters *parameters)
1429 {
1430         ETrustPromptResponse response;
1431         ESource *source;
1432         GTlsCertificate *cert = NULL;
1433         GTlsCertificateFlags cert_errors = 0;
1434         GByteArray *bytes = NULL;
1435         SoupURI *soup_uri;
1436         const gchar *host;
1437         gchar *base64;
1438         gchar *old_host = NULL;
1439         gchar *old_hash = NULL;
1440         gchar *cert_errs_str;
1441         gchar *markup = NULL;
1442         gint issuer_count;
1443
1444         g_return_val_if_fail (
1445                 E_IS_SOURCE_WEBDAV (extension),
1446                 E_TRUST_PROMPT_RESPONSE_REJECT);
1447         g_return_val_if_fail (
1448                 SOUP_IS_MESSAGE (message),
1449                 E_TRUST_PROMPT_RESPONSE_REJECT);
1450         if (parent_source)
1451                 g_return_val_if_fail (
1452                         E_IS_SOURCE (parent_source),
1453                         E_TRUST_PROMPT_RESPONSE_REJECT);
1454         g_return_val_if_fail (
1455                 parameters != NULL,
1456                 E_TRUST_PROMPT_RESPONSE_REJECT);
1457
1458         if (message->status_code != SOUP_STATUS_SSL_FAILED)
1459                 return E_TRUST_PROMPT_RESPONSE_REJECT;
1460
1461         if (!soup_message_get_https_status (message, &cert, &cert_errors) || !cert)
1462                 return E_TRUST_PROMPT_RESPONSE_REJECT;
1463
1464         soup_uri = soup_message_get_uri (message);
1465
1466         if (soup_uri == NULL)
1467                 return E_TRUST_PROMPT_RESPONSE_REJECT;
1468
1469         if (soup_uri_get_host (soup_uri) == NULL)
1470                 return E_TRUST_PROMPT_RESPONSE_REJECT;
1471
1472         g_return_val_if_fail (cert != NULL, E_TRUST_PROMPT_RESPONSE_REJECT);
1473         g_object_get (cert, "certificate", &bytes, NULL);
1474
1475         if (bytes == NULL)
1476                 return E_TRUST_PROMPT_RESPONSE_REJECT;
1477
1478         host = soup_uri_get_host (soup_uri);
1479
1480         if (decode_ssl_trust (extension, &response, &old_host, &old_hash)) {
1481                 gchar *hash;
1482
1483                 hash = g_compute_checksum_for_data (
1484                         G_CHECKSUM_SHA1, bytes->data, bytes->len);
1485
1486                 if (response != E_TRUST_PROMPT_RESPONSE_UNKNOWN &&
1487                     g_strcmp0 (old_host, host) == 0 &&
1488                     g_strcmp0 (old_hash, hash) == 0) {
1489                         g_byte_array_unref (bytes);
1490                         g_free (old_host);
1491                         g_free (old_hash);
1492                         g_free (hash);
1493
1494                         return response;
1495                 }
1496
1497                 g_free (old_host);
1498                 g_free (old_hash);
1499                 g_free (hash);
1500         }
1501
1502         source = e_source_extension_ref_source (E_SOURCE_EXTENSION (extension));
1503         if (source != NULL) {
1504                 const gchar *display_name;
1505                 gchar *bhost = g_strconcat ("<b>", host, "</b>", NULL);
1506                 gchar *bname = NULL;
1507
1508                 display_name = e_source_get_display_name (source);
1509
1510                 if (parent_source != NULL) {
1511                         const gchar *parent_display_name;
1512
1513                         parent_display_name =
1514                                 e_source_get_display_name (parent_source);
1515                         bname = g_strdup_printf (
1516                                 "<b>%s: %s</b>",
1517                                 parent_display_name, display_name);
1518                 }
1519
1520                 if (bname == NULL)
1521                         bname = g_strdup_printf ("<b>%s</b>", display_name);
1522
1523                 if (e_source_has_extension (source, E_SOURCE_EXTENSION_ADDRESS_BOOK)) {
1524                         /* Translators: The first %s is replaced with a host
1525                          * name, like "www.example.com"; the second %s is
1526                          * replaced with actual source name, like
1527                          * "On The Web: My Work" */
1528                         markup = g_strdup_printf (
1529                                 _("SSL certificate for host '%s', used by "
1530                                 "address book '%s', is not trusted. Do you "
1531                                 "wish to accept it?"), bhost, bname);
1532                 } else if (e_source_has_extension (source, E_SOURCE_EXTENSION_CALENDAR)) {
1533                         /* Translators: The first %s is replaced with a
1534                          * host name, like "www.example.com"; the second %s
1535                          * is replaced with actual source name, like
1536                          * "On The Web: My Work" */
1537                         markup = g_strdup_printf (
1538                                 _("SSL certificate for host '%s', used by "
1539                                 "calendar '%s', is not trusted. Do you wish "
1540                                 "to accept it?"), bhost, bname);
1541                 } else if (e_source_has_extension (source, E_SOURCE_EXTENSION_MEMO_LIST)) {
1542                         /* Translators: The first %s is replaced with a
1543                          * host name, like "www.example.com"; the second %s
1544                          * is replaced with actual source name, like
1545                          * "On The Web: My Work" */
1546                         markup = g_strdup_printf (
1547                                 _("SSL certificate for host '%s', used by "
1548                                 "memo list '%s', is not trusted. Do you wish "
1549                                 "to accept it?"), bhost, bname);
1550                 } else if (e_source_has_extension (source, E_SOURCE_EXTENSION_TASK_LIST)) {
1551                         /* Translators: The first %s is replaced with a
1552                          * host name, like "www.example.com"; the second %s
1553                          * is replaced with actual source name, like
1554                          * "On The Web: My Work" */
1555                         markup = g_strdup_printf (
1556                                 _("SSL certificate for host '%s', used by "
1557                                 "task list '%s', is not trusted. Do you wish "
1558                                 "to accept it?"), bhost, bname);
1559                 }
1560
1561                 g_object_unref (source);
1562                 g_free (bname);
1563                 g_free (bhost);
1564         }
1565
1566         base64 = g_base64_encode (bytes->data, bytes->len);
1567         cert_errs_str = g_strdup_printf ("%x", cert_errors);
1568
1569         e_named_parameters_set (parameters, "host", host);
1570         e_named_parameters_set (parameters, "markup", markup);
1571         e_named_parameters_set (parameters, "certificate", base64);
1572         e_named_parameters_set (parameters, "certificate-errors", cert_errs_str);
1573
1574         g_byte_array_unref (bytes);
1575         g_free (cert_errs_str);
1576         g_free (markup);
1577
1578         issuer_count = 0;
1579         while (cert) {
1580                 GTlsCertificate *issuer = NULL;
1581                 g_object_get (cert, "issuer", &issuer, NULL);
1582
1583                 cert = issuer;
1584
1585                 if (cert) {
1586                         bytes = NULL;
1587                         g_object_get (cert, "certificate", &bytes, NULL);
1588
1589                         if (bytes) {
1590                                 base64 = g_base64_encode (bytes->data, bytes->len);
1591                                 if (issuer_count == 0) {
1592                                         e_named_parameters_set (
1593                                         parameters, "issuer", base64);
1594                                 } else {
1595                                         gchar *name;
1596
1597                                         name = g_strdup_printf (
1598                                                 "issuer-%d", issuer_count);
1599                                         e_named_parameters_set (
1600                                                 parameters, name, base64);
1601                                         g_free (name);
1602                                 }
1603
1604                                 g_free (base64);
1605                                 g_byte_array_unref (bytes);
1606                         } else {
1607                                 break;
1608                         }
1609                 }
1610
1611                 issuer_count++;
1612         }
1613
1614         return E_TRUST_PROMPT_RESPONSE_UNKNOWN;
1615 }
1616
1617 static void
1618 webdav_extension_changes_written_cb (GObject *source_object,
1619                                      GAsyncResult *result,
1620                                      gpointer user_data)
1621 {
1622         GError *error = NULL;
1623
1624         e_source_write_finish (E_SOURCE (source_object), result, &error);
1625
1626         if (error) {
1627                 g_message ("%s: Failed with error: %s", G_STRFUNC, error->message);
1628                 g_clear_error (&error);
1629         }
1630 }
1631
1632 /**
1633  * e_source_webdav_store_ssl_trust_prompt:
1634  * @extension: an #ESourceWebdav
1635  * @message: a #SoupMessage with #SOUP_STATUS_SSL_FAILED status code
1636  * @response: user's response from a trust prompt
1637  *
1638  * Stores user's response from a trust prompt, thus it is re-used the next
1639  * time it'll be needed. An #E_TRUST_PROMPT_RESPONSE_UNKNOWN is treated as
1640  * a temporary reject, which means the user will be asked again.
1641  *
1642  * Since: 3.8
1643  **/
1644 void
1645 e_source_webdav_store_ssl_trust_prompt (ESourceWebdav *extension,
1646                                         SoupMessage *message,
1647                                         ETrustPromptResponse response)
1648 {
1649         GTlsCertificate *cert = NULL;
1650         GByteArray *bytes = NULL;
1651         SoupURI *soup_uri;
1652         const gchar *host;
1653         gchar *hash;
1654         gboolean changed;
1655
1656         g_return_if_fail (E_IS_SOURCE_WEBDAV (extension));
1657         g_return_if_fail (SOUP_IS_MESSAGE (message));
1658
1659         if (message->status_code != SOUP_STATUS_SSL_FAILED)
1660                 return;
1661
1662         if (!soup_message_get_https_status (message, &cert, NULL) || !cert)
1663                 return;
1664
1665         soup_uri = soup_message_get_uri (message);
1666         if (!soup_uri || !soup_uri_get_host (soup_uri))
1667                 return;
1668
1669         g_return_if_fail (cert != NULL);
1670         g_object_get (cert, "certificate", &bytes, NULL);
1671
1672         if (!bytes)
1673                 return;
1674
1675         host = soup_uri_get_host (soup_uri);
1676         hash = g_compute_checksum_for_data (G_CHECKSUM_SHA1, bytes->data, bytes->len);
1677
1678         changed = encode_ssl_trust (extension, response, host, hash);
1679
1680         g_byte_array_unref (bytes);
1681         g_free (hash);
1682
1683         if (changed) {
1684                 ESource *source;
1685
1686                 source = e_source_extension_ref_source (
1687                         E_SOURCE_EXTENSION (extension));
1688                 e_source_write (
1689                         source, NULL,
1690                         webdav_extension_changes_written_cb, NULL);
1691                 g_object_unref (source);
1692         }
1693 }
1694
1695 /**
1696  * e_source_webdav_unset_temporary_ssl_trust:
1697  * @extension: an #ESourceWebdav
1698  *
1699  * Unsets temporary trust set on this @extension, but keeps
1700  * it as is for other values.
1701  *
1702  * Since: 3.8
1703  **/
1704 void
1705 e_source_webdav_unset_temporary_ssl_trust (ESourceWebdav *extension)
1706 {
1707         ETrustPromptResponse response = E_TRUST_PROMPT_RESPONSE_UNKNOWN;
1708
1709         g_return_if_fail (E_IS_SOURCE_WEBDAV (extension));
1710
1711         if (!decode_ssl_trust (extension, &response, NULL, NULL) ||
1712             response == E_TRUST_PROMPT_RESPONSE_UNKNOWN ||
1713             response == E_TRUST_PROMPT_RESPONSE_REJECT_TEMPORARILY ||
1714             response == E_TRUST_PROMPT_RESPONSE_ACCEPT_TEMPORARILY)
1715                 e_source_webdav_set_ssl_trust (extension, NULL);
1716 }