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