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.
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.
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/>
20 * SECTION: e-source-webdav
21 * @include: libedataserver/libedataserver.h
22 * @short_description: #ESource extension for WebDAV settings
24 * The #ESourceWebdav extension tracks settings for accessing resources
25 * on a remote WebDAV server.
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.
32 * The #SoupURI is parsed into components and distributed across
33 * several other built-in extensions such as #ESourceAuthentication
34 * and #ESourceSecurity.
36 * Access the extension as follows:
39 * #include <libedataserver/libedataserver.h>
41 * ESourceWebdav *extension;
43 * extension = e_source_get_extension (source, E_SOURCE_EXTENSION_WEBDAV_BACKEND);
51 #include <glib/gi18n-lib.h>
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>
60 #include "e-source-webdav.h"
62 #define E_SOURCE_WEBDAV_GET_PRIVATE(obj) \
63 (G_TYPE_INSTANCE_GET_PRIVATE \
64 ((obj), E_TYPE_SOURCE_WEBDAV, ESourceWebdavPrivate))
66 struct _ESourceWebdavPrivate {
71 gchar *resource_query;
73 gboolean avoid_ifmatch;
74 gboolean calendar_auto_schedule;
75 gboolean ignore_invalid_cert;
82 PROP_CALENDAR_AUTO_SCHEDULE,
85 PROP_IGNORE_INVALID_CERT,
95 E_TYPE_SOURCE_EXTENSION)
98 source_webdav_notify_cb (GObject *object,
100 ESourceWebdav *extension)
102 g_object_notify (G_OBJECT (extension), "soup-uri");
106 source_webdav_user_to_method (GBinding *binding,
107 const GValue *source_value,
108 GValue *target_value,
113 user = g_value_get_string (source_value);
114 if (user == NULL || *user == '\0')
115 g_value_set_string (target_value, "none");
117 g_value_set_string (target_value, "plain/password");
123 source_webdav_update_properties_from_soup_uri (ESourceWebdav *webdav_extension)
126 ESourceExtension *extension;
128 const gchar *extension_name;
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);
136 extension = E_SOURCE_EXTENSION (webdav_extension);
137 source = e_source_extension_ref_source (extension);
141 "resource-path", soup_uri->path,
142 "resource-query", soup_uri->query,
145 extension_name = E_SOURCE_EXTENSION_AUTHENTICATION;
146 extension = e_source_get_extension (source, extension_name);
150 "host", soup_uri->host,
151 "port", soup_uri->port,
152 "user", soup_uri->user,
155 extension_name = E_SOURCE_EXTENSION_SECURITY;
156 extension = e_source_get_extension (source, extension_name);
160 "secure", (soup_uri->scheme == SOUP_URI_SCHEME_HTTPS),
163 g_object_unref (source);
165 soup_uri_free (soup_uri);
169 source_webdav_update_soup_uri_from_properties (ESourceWebdav *webdav_extension)
172 ESourceExtension *extension;
174 const gchar *extension_name;
182 extension = E_SOURCE_EXTENSION (webdav_extension);
183 source = e_source_extension_ref_source (extension);
187 "resource-path", &path,
188 "resource-query", &query,
191 extension_name = E_SOURCE_EXTENSION_AUTHENTICATION;
192 extension = e_source_get_extension (source, extension_name);
201 extension_name = E_SOURCE_EXTENSION_SECURITY;
202 extension = e_source_get_extension (source, extension_name);
209 g_object_unref (source);
211 g_mutex_lock (&webdav_extension->priv->property_lock);
213 soup_uri = webdav_extension->priv->soup_uri;
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);
222 soup_uri_set_user (soup_uri, user);
223 soup_uri_set_host (soup_uri, host);
224 soup_uri_set_port (soup_uri, port);
226 /* SoupURI doesn't like NULL paths. */
227 soup_uri_set_path (soup_uri, (path != NULL) ? path : "");
229 soup_uri_set_query (soup_uri, query);
231 g_mutex_unlock (&webdav_extension->priv->property_lock);
240 source_webdav_set_property (GObject *object,
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));
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));
258 case PROP_DISPLAY_NAME:
259 e_source_webdav_set_display_name (
260 E_SOURCE_WEBDAV (object),
261 g_value_get_string (value));
264 case PROP_EMAIL_ADDRESS:
265 e_source_webdav_set_email_address (
266 E_SOURCE_WEBDAV (object),
267 g_value_get_string (value));
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));
276 case PROP_RESOURCE_PATH:
277 e_source_webdav_set_resource_path (
278 E_SOURCE_WEBDAV (object),
279 g_value_get_string (value));
282 case PROP_RESOURCE_QUERY:
283 e_source_webdav_set_resource_query (
284 E_SOURCE_WEBDAV (object),
285 g_value_get_string (value));
289 e_source_webdav_set_soup_uri (
290 E_SOURCE_WEBDAV (object),
291 g_value_get_boxed (value));
295 e_source_webdav_set_ssl_trust (
296 E_SOURCE_WEBDAV (object),
297 g_value_get_string (value));
301 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
305 source_webdav_get_property (GObject *object,
310 switch (property_id) {
311 case PROP_AVOID_IFMATCH:
312 g_value_set_boolean (
314 e_source_webdav_get_avoid_ifmatch (
315 E_SOURCE_WEBDAV (object)));
318 case PROP_CALENDAR_AUTO_SCHEDULE:
319 g_value_set_boolean (
321 e_source_webdav_get_calendar_auto_schedule (
322 E_SOURCE_WEBDAV (object)));
325 case PROP_DISPLAY_NAME:
326 g_value_take_string (
328 e_source_webdav_dup_display_name (
329 E_SOURCE_WEBDAV (object)));
332 case PROP_EMAIL_ADDRESS:
333 g_value_take_string (
335 e_source_webdav_dup_email_address (
336 E_SOURCE_WEBDAV (object)));
339 case PROP_IGNORE_INVALID_CERT:
340 g_value_set_boolean (
342 e_source_webdav_get_ignore_invalid_cert (
343 E_SOURCE_WEBDAV (object)));
346 case PROP_RESOURCE_PATH:
347 g_value_take_string (
349 e_source_webdav_dup_resource_path (
350 E_SOURCE_WEBDAV (object)));
353 case PROP_RESOURCE_QUERY:
354 g_value_take_string (
356 e_source_webdav_dup_resource_query (
357 E_SOURCE_WEBDAV (object)));
363 e_source_webdav_dup_soup_uri (
364 E_SOURCE_WEBDAV (object)));
368 g_value_take_string (
370 e_source_webdav_dup_ssl_trust (
371 E_SOURCE_WEBDAV (object)));
375 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
379 source_webdav_finalize (GObject *object)
381 ESourceWebdavPrivate *priv;
383 priv = E_SOURCE_WEBDAV_GET_PRIVATE (object);
385 g_mutex_clear (&priv->property_lock);
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);
393 soup_uri_free (priv->soup_uri);
395 /* Chain up to parent's finalize() method. */
396 G_OBJECT_CLASS (e_source_webdav_parent_class)->finalize (object);
400 source_webdav_constructed (GObject *object)
403 ESourceExtension *extension;
404 const gchar *extension_name;
406 /* Chain up to parent's constructed() method. */
407 G_OBJECT_CLASS (e_source_webdav_parent_class)->constructed (object);
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. */
414 extension = E_SOURCE_EXTENSION (object);
415 source = e_source_extension_ref_source (extension);
418 extension, "notify::resource-path",
419 G_CALLBACK (source_webdav_notify_cb), object);
422 extension, "notify::resource-query",
423 G_CALLBACK (source_webdav_notify_cb), object);
425 extension_name = E_SOURCE_EXTENSION_AUTHENTICATION;
426 extension = e_source_get_extension (source, extension_name);
429 extension, "notify::host",
430 G_CALLBACK (source_webdav_notify_cb), object);
433 extension, "notify::port",
434 G_CALLBACK (source_webdav_notify_cb), object);
437 extension, "notify::user",
438 G_CALLBACK (source_webdav_notify_cb), object);
440 /* This updates the authentication method
441 * based on whether a user name was given. */
442 g_object_bind_property_full (
445 G_BINDING_SYNC_CREATE,
446 source_webdav_user_to_method,
448 NULL, (GDestroyNotify) NULL);
450 extension_name = E_SOURCE_EXTENSION_SECURITY;
451 extension = e_source_get_extension (source, extension_name);
454 extension, "notify::secure",
455 G_CALLBACK (source_webdav_notify_cb), object);
457 g_object_unref (source);
461 e_source_webdav_class_init (ESourceWebdavClass *class)
463 GObjectClass *object_class;
464 ESourceExtensionClass *extension_class;
466 g_type_class_add_private (class, sizeof (ESourceWebdavPrivate));
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;
474 extension_class = E_SOURCE_EXTENSION_CLASS (class);
475 extension_class->name = E_SOURCE_EXTENSION_WEBDAV_BACKEND;
477 g_object_class_install_property (
480 g_param_spec_boolean (
483 "Work around a bug in old Apache servers",
487 E_SOURCE_PARAM_SETTING));
489 g_object_class_install_property (
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)",
500 E_SOURCE_PARAM_SETTING));
502 g_object_class_install_property (
505 g_param_spec_string (
508 "Display name of the WebDAV resource",
512 E_SOURCE_PARAM_SETTING));
514 g_object_class_install_property (
517 g_param_spec_string (
520 "The user's email address",
524 E_SOURCE_PARAM_SETTING));
526 g_object_class_install_property (
528 PROP_IGNORE_INVALID_CERT,
529 g_param_spec_boolean (
530 "ignore-invalid-cert",
531 "Ignore Invalid Cert",
532 "Ignore invalid SSL certificates",
536 E_SOURCE_PARAM_SETTING));
538 g_object_class_install_property (
541 g_param_spec_string (
544 "Absolute path to a WebDAV resource",
548 E_SOURCE_PARAM_SETTING));
550 g_object_class_install_property (
553 g_param_spec_string (
556 "Query to access a WebDAV resource",
560 E_SOURCE_PARAM_SETTING));
562 g_object_class_install_property (
568 "WebDAV service as a SoupURI",
572 g_object_class_install_property (
575 g_param_spec_string (
578 "SSL certificate trust setting, "
579 "for invalid server certificates",
583 E_SOURCE_PARAM_SETTING));
587 e_source_webdav_init (ESourceWebdav *extension)
589 extension->priv = E_SOURCE_WEBDAV_GET_PRIVATE (extension);
590 g_mutex_init (&extension->priv->property_lock);
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 ("");
599 * e_source_webdav_get_avoid_ifmatch:
600 * @extension: an #ESourceWebdav
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.
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.
614 * Returns: whether the WebDAV server is known to exhibit the bug
619 e_source_webdav_get_avoid_ifmatch (ESourceWebdav *extension)
621 g_return_val_if_fail (E_IS_SOURCE_WEBDAV (extension), FALSE);
623 return extension->priv->avoid_ifmatch;
627 * e_source_webdav_set_avoid_ifmatch:
628 * @extension: an #ESourceWebdav
629 * @avoid_ifmatch: whether the WebDAV server is known to exhibit the bug
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.
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.
646 e_source_webdav_set_avoid_ifmatch (ESourceWebdav *extension,
647 gboolean avoid_ifmatch)
649 g_return_if_fail (E_IS_SOURCE_WEBDAV (extension));
651 if (extension->priv->avoid_ifmatch == avoid_ifmatch)
654 extension->priv->avoid_ifmatch = avoid_ifmatch;
656 g_object_notify (G_OBJECT (extension), "avoid-ifmatch");
660 * e_source_webdav_get_calendar_auto_schedule:
661 * @extension: an #ESourceWebdav
668 e_source_webdav_get_calendar_auto_schedule (ESourceWebdav *extension)
670 g_return_val_if_fail (E_IS_SOURCE_WEBDAV (extension), FALSE);
672 return extension->priv->calendar_auto_schedule;
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
686 e_source_webdav_set_calendar_auto_schedule (ESourceWebdav *extension,
687 gboolean calendar_auto_schedule)
689 g_return_if_fail (E_IS_SOURCE_WEBDAV (extension));
691 if (extension->priv->calendar_auto_schedule == calendar_auto_schedule)
694 extension->priv->calendar_auto_schedule = calendar_auto_schedule;
696 g_object_notify (G_OBJECT (extension), "calendar-auto-schedule");
700 * e_source_webdav_get_display_name:
701 * @extension: an #ESourceWebdav
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.
707 * Returns: the display name of the WebDAV resource
712 e_source_webdav_get_display_name (ESourceWebdav *extension)
714 g_return_val_if_fail (E_IS_SOURCE_WEBDAV (extension), NULL);
716 return extension->priv->display_name;
720 * e_source_webdav_dup_display_name:
721 * @extension: an #ESourceWebdav
723 * Thread-safe variation of e_source_webdav_get_display_name().
724 * Use this function when accessing @extension from multiple threads.
726 * The returned string should be freed with g_free() when no longer needed.
728 * Returns: a newly-allocated copy of #ESourceWebdav:display-name
733 e_source_webdav_dup_display_name (ESourceWebdav *extension)
735 const gchar *protected;
738 g_return_val_if_fail (E_IS_SOURCE_WEBDAV (extension), NULL);
740 g_mutex_lock (&extension->priv->property_lock);
742 protected = e_source_webdav_get_display_name (extension);
743 duplicate = g_strdup (protected);
745 g_mutex_unlock (&extension->priv->property_lock);
751 * e_source_webdav_set_display_name:
752 * @extension: an #ESourceWebdav
753 * @display_name: (allow-none): the display name of the WebDAV resource,
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.
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
767 e_source_webdav_set_display_name (ESourceWebdav *extension,
768 const gchar *display_name)
770 g_return_if_fail (E_IS_SOURCE_WEBDAV (extension));
772 g_mutex_lock (&extension->priv->property_lock);
774 if (g_strcmp0 (extension->priv->display_name, display_name) == 0) {
775 g_mutex_unlock (&extension->priv->property_lock);
779 g_free (extension->priv->display_name);
780 extension->priv->display_name = e_util_strdup_strip (display_name);
782 g_mutex_unlock (&extension->priv->property_lock);
784 g_object_notify (G_OBJECT (extension), "display-name");
788 * e_source_webdav_get_email_address:
789 * @extension: an #ESourceWebdav
791 * Returns the user's email address which can be passed to a CalDAV server
792 * if the user wishes to receive scheduling messages.
794 * Returns: the user's email address
799 e_source_webdav_get_email_address (ESourceWebdav *extension)
801 g_return_val_if_fail (E_IS_SOURCE_WEBDAV (extension), NULL);
803 return extension->priv->email_address;
807 * e_source_webdav_dup_email_address:
808 * @extension: an #ESourceWebdav
810 * Thread-safe variation of e_source_webdav_get_email_address().
811 * Use this function when accessing @extension from multiple threads.
813 * The returned string should be freed with g_free() when no longer needed.
815 * Returns: the newly-allocated copy of #ESourceWebdav:email-address
820 e_source_webdav_dup_email_address (ESourceWebdav *extension)
822 const gchar *protected;
825 g_return_val_if_fail (E_IS_SOURCE_WEBDAV (extension), NULL);
827 g_mutex_lock (&extension->priv->property_lock);
829 protected = e_source_webdav_get_email_address (extension);
830 duplicate = g_strdup (protected);
832 g_mutex_unlock (&extension->priv->property_lock);
838 * e_source_webdav_set_email_address:
839 * @extension: an #ESourceWebdav
840 * @email_address: (allow-none): the user's email address, or %NULL
842 * Sets the user's email address which can be passed to a CalDAV server if
843 * the user wishes to receive scheduling messages.
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
852 e_source_webdav_set_email_address (ESourceWebdav *extension,
853 const gchar *email_address)
855 g_return_if_fail (E_IS_SOURCE_WEBDAV (extension));
857 g_mutex_lock (&extension->priv->property_lock);
859 if (g_strcmp0 (extension->priv->email_address, email_address) == 0) {
860 g_mutex_unlock (&extension->priv->property_lock);
864 g_free (extension->priv->email_address);
865 extension->priv->email_address = e_util_strdup_strip (email_address);
867 g_mutex_unlock (&extension->priv->property_lock);
869 g_object_notify (G_OBJECT (extension), "email-address");
873 * e_source_webdav_get_ignore_invalid_cert:
874 * @extension: an #ESourceWebdav
876 * Returns %TRUE if invalid SSL certificates should be ignored.
878 * This option allows SSL certificates to be accepted even if they have
879 * signed by an unrecognized Certificate Authority.
881 * Returns: whether invalid SSL certificates should be ignored
885 * Deprecated: 3.8: The trust prompt APIs replace this.
888 e_source_webdav_get_ignore_invalid_cert (ESourceWebdav *extension)
890 g_return_val_if_fail (E_IS_SOURCE_WEBDAV (extension), FALSE);
892 return extension->priv->ignore_invalid_cert;
896 * e_source_webdav_set_ignore_invalid_cert:
897 * @extension: an #ESourceWebdav
898 * @ignore_invalid_cert: whether invalid SSL certificates should be ignored
900 * Sets whether invalid SSL certificates should be ignored.
902 * This option allows SSL certificates to be accepted even if they have
903 * signed by an unrecognized Certificate Authority.
907 * Deprecated: 3.8: The trust prompt APIs replace this.
910 e_source_webdav_set_ignore_invalid_cert (ESourceWebdav *extension,
911 gboolean ignore_invalid_cert)
913 g_return_if_fail (E_IS_SOURCE_WEBDAV (extension));
915 if (extension->priv->ignore_invalid_cert == ignore_invalid_cert)
918 extension->priv->ignore_invalid_cert = ignore_invalid_cert;
920 g_object_notify (G_OBJECT (extension), "ignore-invalid-cert");
924 * e_source_webdav_get_resource_path:
925 * @extension: an #ESourceWebdav
927 * Returns the absolute path to a resource on a WebDAV server.
929 * Returns: the absolute path to a WebDAV resource
934 e_source_webdav_get_resource_path (ESourceWebdav *extension)
936 g_return_val_if_fail (E_IS_SOURCE_WEBDAV (extension), NULL);
938 return extension->priv->resource_path;
942 * e_source_webdav_dup_resource_path:
943 * @extension: an #ESourceWebdav
945 * Thread-safe variation of e_source_webdav_get_resource_path().
946 * Use this function when accessing @extension from multiple threads.
948 * The returned string should be freed with g_free() when no longer needed.
950 * Returns: the newly-allocated copy of #ESourceWebdav:resource-path
955 e_source_webdav_dup_resource_path (ESourceWebdav *extension)
957 const gchar *protected;
960 g_return_val_if_fail (E_IS_SOURCE_WEBDAV (extension), NULL);
962 g_mutex_lock (&extension->priv->property_lock);
964 protected = e_source_webdav_get_resource_path (extension);
965 duplicate = g_strdup (protected);
967 g_mutex_unlock (&extension->priv->property_lock);
973 * e_source_webdav_set_resource_path:
974 * @extension: an #ESourceWebdav
975 * @resource_path: (allow-none): the absolute path to a WebDAV resource,
978 * Sets the absolute path to a resource on a WebDAV server.
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
987 e_source_webdav_set_resource_path (ESourceWebdav *extension,
988 const gchar *resource_path)
990 g_return_if_fail (E_IS_SOURCE_WEBDAV (extension));
992 g_mutex_lock (&extension->priv->property_lock);
994 if (g_strcmp0 (extension->priv->resource_path, resource_path) == 0) {
995 g_mutex_unlock (&extension->priv->property_lock);
999 g_free (extension->priv->resource_path);
1000 extension->priv->resource_path = e_util_strdup_strip (resource_path);
1002 g_mutex_unlock (&extension->priv->property_lock);
1004 g_object_notify (G_OBJECT (extension), "resource-path");
1008 * e_source_webdav_get_resource_query:
1009 * @extension: an #ESourceWebdav
1011 * Returns the URI query required to access a resource on a WebDAV server.
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.
1018 * Returns: the query to access a WebDAV resource
1023 e_source_webdav_get_resource_query (ESourceWebdav *extension)
1025 g_return_val_if_fail (E_IS_SOURCE_WEBDAV (extension), NULL);
1027 return extension->priv->resource_query;
1031 * e_source_webdav_dup_resource_query:
1032 * @extension: an #ESourceWebdav
1034 * Thread-safe variation of e_source_webdav_get_resource_query().
1035 * Use this function when accessing @extension from multiple threads.
1037 * The returned string should be freed with g_free() when no longer needed.
1039 * Returns: the newly-allocated copy of #ESourceWebdav:resource-query
1044 e_source_webdav_dup_resource_query (ESourceWebdav *extension)
1046 const gchar *protected;
1049 g_return_val_if_fail (E_IS_SOURCE_WEBDAV (extension), NULL);
1051 g_mutex_lock (&extension->priv->property_lock);
1053 protected = e_source_webdav_get_resource_query (extension);
1054 duplicate = g_strdup (protected);
1056 g_mutex_unlock (&extension->priv->property_lock);
1062 * e_source_webdav_set_resource_query:
1063 * @extension: an #ESourceWebdav
1064 * @resource_query: (allow-none): the query to access a WebDAV resource,
1067 * Sets the URI query required to access a resource on a WebDAV server.
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.
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
1081 e_source_webdav_set_resource_query (ESourceWebdav *extension,
1082 const gchar *resource_query)
1084 g_return_if_fail (E_IS_SOURCE_WEBDAV (extension));
1086 g_mutex_lock (&extension->priv->property_lock);
1088 if (g_strcmp0 (extension->priv->resource_query, resource_query) == 0) {
1089 g_mutex_unlock (&extension->priv->property_lock);
1093 g_free (extension->priv->resource_query);
1094 extension->priv->resource_query = e_util_strdup_strip (resource_query);
1096 g_mutex_unlock (&extension->priv->property_lock);
1098 g_object_notify (G_OBJECT (extension), "resource-query");
1102 * e_source_webdav_get_ssl_trust:
1103 * @extension: an #ESourceWebdav
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().
1114 * Returns: an SSL certificate trust for the @extension
1119 e_source_webdav_get_ssl_trust (ESourceWebdav *extension)
1121 g_return_val_if_fail (E_IS_SOURCE_WEBDAV (extension), NULL);
1123 return extension->priv->ssl_trust;
1127 * e_source_webdav_dup_ssl_trust:
1128 * @extension: an #ESourceWebdav
1130 * Thread-safe variation of e_source_webdav_get_ssl_trust().
1131 * Use this function when accessing @extension from multiple threads.
1133 * The returned string should be freed with g_free() when no longer needed.
1135 * Returns: the newly-allocated copy of #ESourceWebdav:ssl-trust
1140 e_source_webdav_dup_ssl_trust (ESourceWebdav *extension)
1142 const gchar *protected;
1145 g_return_val_if_fail (E_IS_SOURCE_WEBDAV (extension), NULL);
1147 g_mutex_lock (&extension->priv->property_lock);
1149 protected = e_source_webdav_get_ssl_trust (extension);
1150 duplicate = g_strdup (protected);
1152 g_mutex_unlock (&extension->priv->property_lock);
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
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.
1168 e_source_webdav_set_ssl_trust (ESourceWebdav *extension,
1169 const gchar *ssl_trust)
1171 g_return_if_fail (E_IS_SOURCE_WEBDAV (extension));
1173 g_mutex_lock (&extension->priv->property_lock);
1175 if (g_strcmp0 (extension->priv->ssl_trust, ssl_trust) == 0) {
1176 g_mutex_unlock (&extension->priv->property_lock);
1180 g_free (extension->priv->ssl_trust);
1181 extension->priv->ssl_trust = g_strdup (ssl_trust);
1183 g_mutex_unlock (&extension->priv->property_lock);
1185 g_object_notify (G_OBJECT (extension), "ssl-trust");
1189 * e_source_webdav_dup_soup_uri:
1190 * @extension: an #ESourceWebdav
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().
1197 * Returns: (transfer full): a newly-allocated #SoupURI
1202 e_source_webdav_dup_soup_uri (ESourceWebdav *extension)
1206 g_return_val_if_fail (E_IS_SOURCE_WEBDAV (extension), NULL);
1208 /* Keep this outside of the property lock. */
1209 source_webdav_update_soup_uri_from_properties (extension);
1211 g_mutex_lock (&extension->priv->property_lock);
1213 duplicate = soup_uri_copy (extension->priv->soup_uri);
1215 g_mutex_unlock (&extension->priv->property_lock);
1221 * e_source_webdav_set_soup_uri:
1222 * @extension: an #ESourceWebdav
1223 * @soup_uri: a #SoupURI
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
1233 e_source_webdav_set_soup_uri (ESourceWebdav *extension,
1236 g_return_if_fail (E_IS_SOURCE_WEBDAV (extension));
1237 g_return_if_fail (SOUP_URI_IS_VALID (soup_uri));
1239 g_mutex_lock (&extension->priv->property_lock);
1241 /* Do not test for URI equality because our
1242 * internal SoupURI might not be up-to-date. */
1244 soup_uri_free (extension->priv->soup_uri);
1245 extension->priv->soup_uri = soup_uri_copy (soup_uri);
1247 g_mutex_unlock (&extension->priv->property_lock);
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));
1256 decode_ssl_trust (ESourceWebdav *extension,
1257 ETrustPromptResponse *response,
1261 gchar *ssl_trust, **strv;
1263 g_return_val_if_fail (E_IS_SOURCE_WEBDAV (extension), FALSE);
1265 ssl_trust = e_source_webdav_dup_ssl_trust (extension);
1266 if (!ssl_trust || !*ssl_trust) {
1271 strv = g_strsplit (ssl_trust, "|", 3);
1272 if (!strv || !strv[0] || !strv[1] || !strv[2] || strv[3]) {
1279 const gchar *resp = strv[0];
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;
1290 *response = E_TRUST_PROMPT_RESPONSE_UNKNOWN;
1294 *host = g_strdup (strv[1]);
1297 *hash = g_strdup (strv[2]);
1306 encode_ssl_trust (ESourceWebdav *extension,
1307 ETrustPromptResponse response,
1315 g_return_val_if_fail (E_IS_SOURCE_WEBDAV (extension), FALSE);
1317 if (response == E_TRUST_PROMPT_RESPONSE_REJECT)
1319 else if (response == E_TRUST_PROMPT_RESPONSE_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";
1326 resp = "temporary-reject";
1328 if (host && *host && hash && *hash) {
1329 ssl_trust = g_strconcat (resp, "|", host, "|", hash, NULL);
1334 changed = g_strcmp0 (extension->priv->ssl_trust, ssl_trust) != 0;
1337 e_source_webdav_set_ssl_trust (extension, ssl_trust);
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
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.
1356 * Returns: What to do with SSL connection, where
1357 * #E_TRUST_PROMPT_RESPONSE_UNKNOWN means 'ask a user, with
1358 * populated parameters'.
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.
1366 ETrustPromptResponse
1367 e_source_webdav_prepare_ssl_trust_prompt (ESourceWebdav *extension,
1368 SoupMessage *message,
1369 ESourceRegistry *registry,
1370 ENamedParameters *parameters)
1372 ESource *source, *parent_source = NULL;
1373 ETrustPromptResponse res;
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 (
1386 E_TRUST_PROMPT_RESPONSE_REJECT);
1388 source = e_source_extension_ref_source (E_SOURCE_EXTENSION (extension));
1389 if (source != NULL) {
1390 const gchar *parent_uid;
1392 parent_uid = e_source_get_parent (source);
1394 if (parent_uid != NULL)
1395 parent_source = e_source_registry_ref_source (
1396 registry, parent_uid);
1398 g_object_unref (source);
1401 res = e_source_webdav_prepare_ssl_trust_prompt_with_parent (
1402 extension, message, parent_source, parameters);
1405 g_object_unref (parent_source);
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
1417 * The same as e_source_webdav_prepare_ssl_trust_prompt(), only takes
1418 * @parent_source directly, instead of an #ESourceRegistry.
1420 * See e_source_webdav_prepare_ssl_trust_prompt() for more details.
1424 ETrustPromptResponse
1425 e_source_webdav_prepare_ssl_trust_prompt_with_parent (ESourceWebdav *extension,
1426 SoupMessage *message,
1427 ESource *parent_source,
1428 ENamedParameters *parameters)
1430 ETrustPromptResponse response;
1432 GTlsCertificate *cert = NULL;
1433 GTlsCertificateFlags cert_errors = 0;
1434 GByteArray *bytes = NULL;
1438 gchar *old_host = NULL;
1439 gchar *old_hash = NULL;
1440 gchar *cert_errs_str;
1441 gchar *markup = NULL;
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);
1451 g_return_val_if_fail (
1452 E_IS_SOURCE (parent_source),
1453 E_TRUST_PROMPT_RESPONSE_REJECT);
1454 g_return_val_if_fail (
1456 E_TRUST_PROMPT_RESPONSE_REJECT);
1458 if (message->status_code != SOUP_STATUS_SSL_FAILED)
1459 return E_TRUST_PROMPT_RESPONSE_REJECT;
1461 if (!soup_message_get_https_status (message, &cert, &cert_errors) || !cert)
1462 return E_TRUST_PROMPT_RESPONSE_REJECT;
1464 soup_uri = soup_message_get_uri (message);
1466 if (soup_uri == NULL)
1467 return E_TRUST_PROMPT_RESPONSE_REJECT;
1469 if (soup_uri_get_host (soup_uri) == NULL)
1470 return E_TRUST_PROMPT_RESPONSE_REJECT;
1472 g_return_val_if_fail (cert != NULL, E_TRUST_PROMPT_RESPONSE_REJECT);
1473 g_object_get (cert, "certificate", &bytes, NULL);
1476 return E_TRUST_PROMPT_RESPONSE_REJECT;
1478 host = soup_uri_get_host (soup_uri);
1480 if (decode_ssl_trust (extension, &response, &old_host, &old_hash)) {
1483 hash = g_compute_checksum_for_data (
1484 G_CHECKSUM_SHA1, bytes->data, bytes->len);
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);
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;
1508 display_name = e_source_get_display_name (source);
1510 if (parent_source != NULL) {
1511 const gchar *parent_display_name;
1513 parent_display_name =
1514 e_source_get_display_name (parent_source);
1515 bname = g_strdup_printf (
1517 parent_display_name, display_name);
1521 bname = g_strdup_printf ("<b>%s</b>", display_name);
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);
1561 g_object_unref (source);
1566 base64 = g_base64_encode (bytes->data, bytes->len);
1567 cert_errs_str = g_strdup_printf ("%x", cert_errors);
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);
1574 g_byte_array_unref (bytes);
1575 g_free (cert_errs_str);
1580 GTlsCertificate *issuer = NULL;
1581 g_object_get (cert, "issuer", &issuer, NULL);
1587 g_object_get (cert, "certificate", &bytes, NULL);
1590 base64 = g_base64_encode (bytes->data, bytes->len);
1591 if (issuer_count == 0) {
1592 e_named_parameters_set (
1593 parameters, "issuer", base64);
1597 name = g_strdup_printf (
1598 "issuer-%d", issuer_count);
1599 e_named_parameters_set (
1600 parameters, name, base64);
1605 g_byte_array_unref (bytes);
1614 return E_TRUST_PROMPT_RESPONSE_UNKNOWN;
1618 webdav_extension_changes_written_cb (GObject *source_object,
1619 GAsyncResult *result,
1622 GError *error = NULL;
1624 e_source_write_finish (E_SOURCE (source_object), result, &error);
1627 g_message ("%s: Failed with error: %s", G_STRFUNC, error->message);
1628 g_clear_error (&error);
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
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.
1645 e_source_webdav_store_ssl_trust_prompt (ESourceWebdav *extension,
1646 SoupMessage *message,
1647 ETrustPromptResponse response)
1649 GTlsCertificate *cert = NULL;
1650 GByteArray *bytes = NULL;
1656 g_return_if_fail (E_IS_SOURCE_WEBDAV (extension));
1657 g_return_if_fail (SOUP_IS_MESSAGE (message));
1659 if (message->status_code != SOUP_STATUS_SSL_FAILED)
1662 if (!soup_message_get_https_status (message, &cert, NULL) || !cert)
1665 soup_uri = soup_message_get_uri (message);
1666 if (!soup_uri || !soup_uri_get_host (soup_uri))
1669 g_return_if_fail (cert != NULL);
1670 g_object_get (cert, "certificate", &bytes, NULL);
1675 host = soup_uri_get_host (soup_uri);
1676 hash = g_compute_checksum_for_data (G_CHECKSUM_SHA1, bytes->data, bytes->len);
1678 changed = encode_ssl_trust (extension, response, host, hash);
1680 g_byte_array_unref (bytes);
1686 source = e_source_extension_ref_source (
1687 E_SOURCE_EXTENSION (extension));
1690 webdav_extension_changes_written_cb, NULL);
1691 g_object_unref (source);
1696 * e_source_webdav_unset_temporary_ssl_trust:
1697 * @extension: an #ESourceWebdav
1699 * Unsets temporary trust set on this @extension, but keeps
1700 * it as is for other values.
1705 e_source_webdav_unset_temporary_ssl_trust (ESourceWebdav *extension)
1707 ETrustPromptResponse response = E_TRUST_PROMPT_RESPONSE_UNKNOWN;
1709 g_return_if_fail (E_IS_SOURCE_WEBDAV (extension));
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);