2 * Copyright (C) 2015 Red Hat, Inc. (www.redhat.com)
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.
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
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/>.
18 #include "evolution-data-server-config.h"
21 #include <glib/gi18n-lib.h>
25 #include <libedataserver/libedataserver.h>
27 #include "e-cell-renderer-color.h"
28 #include "e-trust-prompt.h"
29 #include "e-webdav-discover-widget.h"
31 #define WEBDAV_DISCOVER_CONTENT_KEY "e-webdav-discover-content-widget-key"
32 #define WEBDAV_DISCOVER_CONTENT_ENTRY_KEY "e-webdav-discover-content-widget-entry-key"
33 #define WEBDAV_DISCOVER_CONTENT_DATA_KEY "e-webdav-discover-content-widget-data-key"
38 COL_DISPLAY_NAME_STRING
,
40 COL_DESCRIPTION_STRING
,
43 COL_SHOW_COLOR_BOOLEAN
,
47 typedef struct _EWebDAVDiscoverContentData
{
48 ECredentialsPrompter
*credentials_prompter
;
51 guint supports_filter
;
53 GtkTreeView
*sources_tree_view
; /* not referenced */
54 GtkComboBox
*email_addresses_combo
; /* not referenced */
55 GtkInfoBar
*info_bar
; /* not referenced */
56 } EWebDAVDiscoverContentData
;
59 e_webdav_discover_content_data_free (gpointer ptr
)
61 EWebDAVDiscoverContentData
*data
= ptr
;
64 g_clear_object (&data
->credentials_prompter
);
65 g_clear_object (&data
->source
);
66 g_free (data
->base_url
);
72 * e_webdav_discover_content_new:
73 * @credentials_prompter: an #ECredentialsPrompter to use to ask for credentials
74 * @source: (allow-none): optional #ESource to use for authentication, or %NULL
75 * @base_url: (allow-none): optional base URL to use for discovery, or %NULL
76 * @supports_filter: a bit-or of #EWebDAVDiscoverSupports, a filter to limit what source
77 * types will be shown in the dialog content; use %E_WEBDAV_DISCOVER_SUPPORTS_NONE
80 * Creates a new WebDAV discovery content, which is a #GtkGrid containing necessary
81 * widgets to provide a UI interface for a user to search and select for available
82 * WebDAV (CalDAV or CardDAV) sources provided by the given server. Do not pack
83 * anything into this content, its content can be changed dynamically.
85 * Returns: (transfer full): a new WebDAV discovery content widget.
90 e_webdav_discover_content_new (ECredentialsPrompter
*credentials_prompter
,
92 const gchar
*base_url
,
93 guint supports_filter
)
95 EWebDAVDiscoverContentData
*data
;
96 GtkWidget
*content
, *scrolled_window
, *tree_view
;
97 GtkTreeViewColumn
*column
;
98 GtkCellRenderer
*renderer
;
99 GtkListStore
*list_store
;
102 g_return_val_if_fail (E_IS_CREDENTIALS_PROMPTER (credentials_prompter
), NULL
);
103 g_return_val_if_fail (base_url
!= NULL
, NULL
);
105 data
= g_new0 (EWebDAVDiscoverContentData
, 1);
106 data
->credentials_prompter
= g_object_ref (credentials_prompter
);
107 data
->source
= source
? g_object_ref (source
) : NULL
;
108 data
->base_url
= g_strdup (base_url
);
109 data
->supports_filter
= supports_filter
;
111 content
= gtk_grid_new ();
112 grid
= GTK_GRID (content
);
113 gtk_container_set_border_width (GTK_CONTAINER (grid
), 4);
114 gtk_grid_set_row_spacing (grid
, 4);
115 gtk_grid_set_column_spacing (grid
, 4);
117 g_object_set_data_full (G_OBJECT (content
), WEBDAV_DISCOVER_CONTENT_DATA_KEY
, data
, e_webdav_discover_content_data_free
);
119 list_store
= gtk_list_store_new (N_COLUMNS
,
120 G_TYPE_STRING
, /* COL_HREF_STRING */
121 G_TYPE_UINT
, /* COL_SUPPORTS_UINT */
122 G_TYPE_STRING
, /* COL_DISPLAY_NAME_STRING */
123 G_TYPE_STRING
, /* COL_COLOR_STRING */
124 G_TYPE_STRING
, /* COL_DESCRIPTION_STRING */
125 G_TYPE_STRING
, /* COL_SUPPORTS_STRING */
126 GDK_TYPE_RGBA
, /* COL_COLOR_GDKRGBA */
127 G_TYPE_BOOLEAN
); /* COL_SHOW_COLOR_BOOLEAN */
129 tree_view
= gtk_tree_view_new_with_model (GTK_TREE_MODEL (list_store
));
130 g_object_unref (list_store
);
132 g_object_set (G_OBJECT (tree_view
),
135 "halign", GTK_ALIGN_FILL
,
136 "valign", GTK_ALIGN_FILL
,
139 scrolled_window
= gtk_scrolled_window_new (NULL
, NULL
);
140 gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (scrolled_window
),
141 GTK_POLICY_AUTOMATIC
, GTK_POLICY_AUTOMATIC
);
143 gtk_container_add (GTK_CONTAINER (scrolled_window
), tree_view
);
144 gtk_grid_attach (grid
, scrolled_window
, 0, 0, 1, 1);
146 data
->sources_tree_view
= GTK_TREE_VIEW (tree_view
);
148 renderer
= e_cell_renderer_color_new ();
149 g_object_set (G_OBJECT (renderer
), "mode", GTK_CELL_RENDERER_MODE_ACTIVATABLE
, NULL
);
151 column
= gtk_tree_view_column_new_with_attributes (_("Name"), renderer
, "rgba", COL_COLOR_GDKRGBA
, "visible", COL_SHOW_COLOR_BOOLEAN
, NULL
);
152 gtk_tree_view_append_column (data
->sources_tree_view
, column
);
154 renderer
= gtk_cell_renderer_text_new ();
155 gtk_tree_view_column_pack_start (column
, renderer
, FALSE
);
156 gtk_tree_view_column_add_attribute (column
, renderer
, "markup", COL_DESCRIPTION_STRING
);
157 g_object_set (G_OBJECT (renderer
),
158 "max-width-chars", 60,
159 "wrap-mode", PANGO_WRAP_WORD_CHAR
,
163 renderer
= gtk_cell_renderer_text_new ();
164 column
= gtk_tree_view_column_new_with_attributes (_("Supports"), renderer
, "text", COL_SUPPORTS_STRING
, NULL
);
165 gtk_tree_view_append_column (data
->sources_tree_view
, column
);
167 if (!supports_filter
|| (supports_filter
& (E_WEBDAV_DISCOVER_SUPPORTS_EVENTS
|
168 E_WEBDAV_DISCOVER_SUPPORTS_MEMOS
| E_WEBDAV_DISCOVER_SUPPORTS_TASKS
)) != 0) {
169 GtkWidget
*widget
, *box
;
171 widget
= gtk_combo_box_text_new ();
172 data
->email_addresses_combo
= GTK_COMBO_BOX (widget
);
174 box
= gtk_box_new (GTK_ORIENTATION_HORIZONTAL
, 2);
175 widget
= gtk_label_new_with_mnemonic (_("_User mail:"));
176 gtk_label_set_mnemonic_widget (GTK_LABEL (widget
), GTK_WIDGET (data
->email_addresses_combo
));
178 gtk_container_add (GTK_CONTAINER (box
), widget
);
179 gtk_container_add (GTK_CONTAINER (box
), GTK_WIDGET (data
->email_addresses_combo
));
181 g_object_set (G_OBJECT (widget
),
184 "halign", GTK_ALIGN_START
,
185 "valign", GTK_ALIGN_CENTER
,
188 g_object_set (G_OBJECT (data
->email_addresses_combo
),
191 "halign", GTK_ALIGN_FILL
,
192 "valign", GTK_ALIGN_START
,
195 g_object_set (G_OBJECT (box
),
198 "halign", GTK_ALIGN_FILL
,
199 "valign", GTK_ALIGN_START
,
202 gtk_grid_attach (grid
, box
, 0, 1, 1, 1);
205 gtk_widget_show_all (content
);
211 * e_webdav_discover_content_get_tree_selection:
212 * @content: a WebDAV discovery content, created by e_webdav_discover_content_new()
214 * Returns inner #GtkTreeViewSelection. This is meant to be able to connect
215 * to its "changed" signal and update other parts of the parent widgets accordingly.
217 * Returns: (transfer none): inner #GtkTreeViewSelection
222 e_webdav_discover_content_get_tree_selection (GtkWidget
*content
)
224 EWebDAVDiscoverContentData
*data
;
226 g_return_val_if_fail (GTK_IS_GRID (content
), NULL
);
228 data
= g_object_get_data (G_OBJECT (content
), WEBDAV_DISCOVER_CONTENT_DATA_KEY
);
229 g_return_val_if_fail (data
!= NULL
, NULL
);
231 return gtk_tree_view_get_selection (data
->sources_tree_view
);
235 * e_webdav_discover_content_set_multiselect:
236 * @content: a WebDAV discovery content, created by e_webdav_discover_content_new()
237 * @multiselect: whether multiselect is allowed
239 * Sets whether the WebDAV discovery content allows multiselect.
244 e_webdav_discover_content_set_multiselect (GtkWidget
*content
,
245 gboolean multiselect
)
247 EWebDAVDiscoverContentData
*data
;
248 GtkTreeSelection
*selection
;
250 g_return_if_fail (GTK_IS_GRID (content
));
252 data
= g_object_get_data (G_OBJECT (content
), WEBDAV_DISCOVER_CONTENT_DATA_KEY
);
253 g_return_if_fail (data
!= NULL
);
255 selection
= gtk_tree_view_get_selection (data
->sources_tree_view
);
256 gtk_tree_selection_set_mode (selection
, multiselect
? GTK_SELECTION_MULTIPLE
: GTK_SELECTION_SINGLE
);
260 * e_webdav_discover_content_get_multiselect:
261 * @content: a WebDAV discovery content, created by e_webdav_discover_content_new()
263 * Returns: whether multiselect is allowed for the @content.
268 e_webdav_discover_content_get_multiselect (GtkWidget
*content
)
270 EWebDAVDiscoverContentData
*data
;
271 GtkTreeSelection
*selection
;
273 g_return_val_if_fail (GTK_IS_GRID (content
), FALSE
);
275 data
= g_object_get_data (G_OBJECT (content
), WEBDAV_DISCOVER_CONTENT_DATA_KEY
);
276 g_return_val_if_fail (data
!= NULL
, FALSE
);
278 selection
= gtk_tree_view_get_selection (data
->sources_tree_view
);
279 return gtk_tree_selection_get_mode (selection
) == GTK_SELECTION_MULTIPLE
;
283 * e_webdav_discover_content_set_base_url:
284 * @content: a WebDAV discovery content, created by e_webdav_discover_content_new()
286 * Sets base URL for the @content. This is used to overwrite the one set on
287 * the #ESource from the creation time. The URL can be either a full URL, a path
293 e_webdav_discover_content_set_base_url (GtkWidget
*content
,
294 const gchar
*base_url
)
296 EWebDAVDiscoverContentData
*data
;
298 g_return_if_fail (GTK_IS_GRID (content
));
299 g_return_if_fail (base_url
!= NULL
);
301 data
= g_object_get_data (G_OBJECT (content
), WEBDAV_DISCOVER_CONTENT_DATA_KEY
);
302 g_return_if_fail (data
!= NULL
);
304 if (g_strcmp0 (base_url
, data
->base_url
) != 0) {
305 g_free (data
->base_url
);
306 data
->base_url
= g_strdup (base_url
);
311 * e_webdav_discover_content_get_base_url:
312 * @content: a WebDAV discovery content, created by e_webdav_discover_content_new()
314 * Returns currently set base URL for the @content. This is used to overwrite the one
315 * set on the #ESource from the creation time. The URL can be either a full URL, a path
318 * Returns: currently set base URL for the @content.
323 e_webdav_discover_content_get_base_url (GtkWidget
*content
)
325 EWebDAVDiscoverContentData
*data
;
327 g_return_val_if_fail (GTK_IS_GRID (content
), NULL
);
329 data
= g_object_get_data (G_OBJECT (content
), WEBDAV_DISCOVER_CONTENT_DATA_KEY
);
330 g_return_val_if_fail (data
!= NULL
, NULL
);
332 return data
->base_url
;
336 * e_webdav_discover_content_get_selected:
337 * @content: a WebDAV discovery content, created by e_webdav_discover_content_new()
338 * @index: an index of the selected source; counts from 0
339 * @out_href: (out): an output location for the URL of the selected source
340 * @out_supports: (out): an output location of a bit-or of #EWebDAVDiscoverSupports, the set
341 * of source types this server source location supports
342 * @out_display_name: (out): an output location of the sources display name
343 * @out_color: (out): an output location of the string representation of the color
344 * for the source, as set on the server
346 * Returns information about selected source at index @index. The function can be called
347 * multiple times, with the index starting at zero and as long as it doesn't return %FALSE.
348 * If the @content doesn't have allowed multiselection, then the only valid @index is 0.
350 * All the @out_href, @out_display_name and @out_color are newly allocated strings, which should
351 * be freed with g_free(), when no longer needed.
353 * Returns: %TRUE, when a selected source of index @index exists, %FALSE otherwise.
358 e_webdav_discover_content_get_selected (GtkWidget
*content
,
362 gchar
**out_display_name
,
365 EWebDAVDiscoverContentData
*data
;
366 GtkTreeSelection
*selection
;
367 GtkTreeModel
*model
= NULL
;
368 GList
*selected_rows
, *link
;
369 gboolean success
= FALSE
;
371 g_return_val_if_fail (GTK_IS_GRID (content
), FALSE
);
372 g_return_val_if_fail (index
>= 0, FALSE
);
373 g_return_val_if_fail (out_href
!= NULL
, FALSE
);
374 g_return_val_if_fail (out_supports
!= NULL
, FALSE
);
375 g_return_val_if_fail (out_display_name
!= NULL
, FALSE
);
376 g_return_val_if_fail (out_color
!= NULL
, FALSE
);
378 data
= g_object_get_data (G_OBJECT (content
), WEBDAV_DISCOVER_CONTENT_DATA_KEY
);
379 g_return_val_if_fail (data
!= NULL
, FALSE
);
381 selection
= gtk_tree_view_get_selection (data
->sources_tree_view
);
382 selected_rows
= gtk_tree_selection_get_selected_rows (selection
, &model
);
384 for (link
= selected_rows
; link
&& index
> 0; link
= g_list_next (link
)) {
388 if (index
== 0 && link
) {
389 GtkTreePath
*path
= link
->data
;
394 success
= gtk_tree_model_get_iter (model
, &iter
, path
);
396 gtk_tree_model_get (model
, &iter
,
397 COL_HREF_STRING
, out_href
,
398 COL_SUPPORTS_UINT
, out_supports
,
399 COL_DISPLAY_NAME_STRING
, out_display_name
,
400 COL_COLOR_STRING
, out_color
,
406 g_list_free_full (selected_rows
, (GDestroyNotify
) gtk_tree_path_free
);
412 * e_webdav_discover_content_get_user_address:
413 * @content: a WebDAV discovery content, created by e_webdav_discover_content_new()
415 * Get currently selected user address in the @content, if the server returned any.
416 * This value has meaning only with calendar sources.
418 * Returns: (transfer full): currently selected user address. The returned string
419 * is newly allocated and should be freed with g_free() when no longer needed.
420 * If there are none addresses provided by the server, or no calendar sources
421 * were found, then %NULL is returned instead.
426 e_webdav_discover_content_get_user_address (GtkWidget
*content
)
428 EWebDAVDiscoverContentData
*data
;
431 g_return_val_if_fail (GTK_IS_GRID (content
), NULL
);
433 data
= g_object_get_data (G_OBJECT (content
), WEBDAV_DISCOVER_CONTENT_DATA_KEY
);
434 g_return_val_if_fail (data
!= NULL
, NULL
);
436 if (!data
->email_addresses_combo
)
439 active_text
= gtk_combo_box_text_get_active_text (GTK_COMBO_BOX_TEXT (data
->email_addresses_combo
));
440 if (active_text
&& !*active_text
) {
441 g_free (active_text
);
449 e_webdav_discover_content_fill_discovered_sources (GtkTreeView
*tree_view
,
450 guint supports_filter
,
451 GSList
*discovered_sources
)
453 GtkListStore
*list_store
;
458 /* It's okay to pass NULL here */
462 g_return_if_fail (GTK_IS_TREE_VIEW (tree_view
));
464 model
= gtk_tree_view_get_model (tree_view
);
465 list_store
= GTK_LIST_STORE (model
);
466 gtk_list_store_clear (list_store
);
468 for (link
= discovered_sources
; link
; link
= g_slist_next (link
)) {
469 const EWebDAVDiscoveredSource
*source
= link
->data
;
472 gchar
*description_markup
, *colorstr
= NULL
;
473 gboolean show_color
= FALSE
;
476 if (!source
|| (supports_filter
&& (source
->supports
& supports_filter
) == 0) || !source
->display_name
)
479 if (source
->color
&& *source
->color
) {
482 if (gdk_rgba_parse (&rgba
, source
->color
)) {
484 } else if (sscanf (source
->color
, "#%02x%02x%02x", &rr
, &gg
, &bb
) == 3) {
485 rgba
.red
= ((gdouble
) rr
) / 255.0;
486 rgba
.green
= ((gdouble
) gg
) / 255.0;
487 rgba
.blue
= ((gdouble
) bb
) / 255.0;
494 rr
= 0xFF * rgba
.red
;
495 gg
= 0xFF * rgba
.green
;
496 bb
= 0xFF * rgba
.blue
;
498 colorstr
= g_strdup_printf ("#%02x%02x%02x", rr
& 0xFF, gg
& 0xFF, bb
& 0xFF);
502 if (source
->description
&& *source
->description
) {
503 description_markup
= g_markup_printf_escaped ("<b>%s</b>\n<small>%s</small>",
504 source
->display_name
, source
->description
);
506 description_markup
= g_markup_printf_escaped ("<b>%s</b>",
507 source
->display_name
);
510 supports_bits
= source
->supports
;
511 supports
= g_string_new ("");
513 #define addbit(flg, cpt) { \
514 if (((flg) & supports_bits) != 0) { \
516 g_string_append (supports, ", "); \
517 g_string_append (supports, cpt); \
521 addbit (E_WEBDAV_DISCOVER_SUPPORTS_CONTACTS
, C_("WebDAVDiscover", "Contacts"));
522 addbit (E_WEBDAV_DISCOVER_SUPPORTS_EVENTS
, C_("WebDAVDiscover", "Events"));
523 addbit (E_WEBDAV_DISCOVER_SUPPORTS_MEMOS
, C_("WebDAVDiscover", "Memos"));
524 addbit (E_WEBDAV_DISCOVER_SUPPORTS_TASKS
, C_("WebDAVDiscover", "Tasks"));
528 gtk_list_store_append (list_store
, &iter
);
529 gtk_list_store_set (list_store
, &iter
,
530 COL_HREF_STRING
, source
->href
,
531 COL_SUPPORTS_UINT
, source
->supports
,
532 COL_DISPLAY_NAME_STRING
, source
->display_name
,
533 COL_COLOR_STRING
, colorstr
,
534 COL_DESCRIPTION_STRING
, description_markup
,
535 COL_SUPPORTS_STRING
, supports
->str
,
536 COL_COLOR_GDKRGBA
, show_color
? &rgba
: NULL
,
537 COL_SHOW_COLOR_BOOLEAN
, show_color
,
540 g_free (description_markup
);
542 g_string_free (supports
, TRUE
);
547 e_webdav_discover_content_fill_calendar_emails (GtkComboBox
*combo_box
,
548 GSList
*calendar_user_addresses
)
550 GtkComboBoxText
*text_combo
;
551 gboolean any_added
= FALSE
;
554 /* It's okay to pass NULL here */
558 g_return_if_fail (GTK_IS_COMBO_BOX_TEXT (combo_box
));
560 text_combo
= GTK_COMBO_BOX_TEXT (combo_box
);
562 gtk_combo_box_text_remove_all (text_combo
);
564 for (link
= calendar_user_addresses
; link
; link
= g_slist_next (link
)) {
565 const gchar
*address
= link
->data
;
567 if (address
&& *address
) {
568 gtk_combo_box_text_append_text (text_combo
, address
);
574 gtk_combo_box_set_active (combo_box
, 0);
577 typedef struct _RefreshData
{
579 GCancellable
*cancellable
;
580 GSimpleAsyncResult
*simple
;
582 ENamedParameters
*credentials
;
583 ESourceRegistry
*registry
;
587 refresh_data_free (gpointer ptr
)
589 RefreshData
*rd
= ptr
;
593 EWebDAVDiscoverContentData
*data
;
595 data
= g_object_get_data (G_OBJECT (rd
->content
), WEBDAV_DISCOVER_CONTENT_DATA_KEY
);
598 if (data
->info_bar
&& gtk_info_bar_get_message_type (data
->info_bar
) == GTK_MESSAGE_INFO
) {
599 gtk_widget_destroy (GTK_WIDGET (data
->info_bar
));
600 data
->info_bar
= NULL
;
603 gtk_widget_set_sensitive (GTK_WIDGET (data
->sources_tree_view
), TRUE
);
604 if (data
->email_addresses_combo
)
605 gtk_widget_set_sensitive (GTK_WIDGET (data
->email_addresses_combo
), TRUE
);
609 g_clear_object (&rd
->content
);
610 g_clear_object (&rd
->cancellable
);
611 g_clear_object (&rd
->simple
);
612 g_clear_object (&rd
->registry
);
613 g_free (rd
->base_url
);
614 e_named_parameters_free (rd
->credentials
);
620 e_webdav_discover_content_refresh_done_cb (GObject
*source_object
,
621 GAsyncResult
*result
,
625 e_webdav_discover_content_trust_prompt_done_cb (GObject
*source_object
,
626 GAsyncResult
*result
,
629 ETrustPromptResponse response
= E_TRUST_PROMPT_RESPONSE_UNKNOWN
;
631 RefreshData
*rd
= user_data
;
632 GError
*local_error
= NULL
;
634 g_return_if_fail (E_IS_SOURCE (source_object
));
635 g_return_if_fail (rd
!= NULL
);
637 source
= E_SOURCE (source_object
);
638 if (!e_trust_prompt_run_for_source_finish (source
, result
, &response
, &local_error
)) {
639 g_simple_async_result_take_error (rd
->simple
, local_error
);
641 g_simple_async_result_complete (rd
->simple
);
642 refresh_data_free (rd
);
643 } else if (response
== E_TRUST_PROMPT_RESPONSE_ACCEPT
|| response
== E_TRUST_PROMPT_RESPONSE_ACCEPT_TEMPORARILY
) {
644 /* Use NULL credentials to reuse those from the last time. */
645 e_webdav_discover_sources_full (source
, rd
->base_url
, E_WEBDAV_DISCOVER_SUPPORTS_NONE
, rd
->credentials
,
646 rd
->registry
? (EWebDAVDiscoverRefSourceFunc
) e_source_registry_ref_source
: NULL
, rd
->registry
,
647 rd
->cancellable
, e_webdav_discover_content_refresh_done_cb
, rd
);
649 g_cancellable_cancel (rd
->cancellable
);
650 g_warn_if_fail (g_cancellable_set_error_if_cancelled (rd
->cancellable
, &local_error
));
651 g_simple_async_result_take_error (rd
->simple
, local_error
);
653 g_simple_async_result_complete (rd
->simple
);
654 refresh_data_free (rd
);
657 g_clear_error (&local_error
);
661 e_webdav_discover_content_credentials_prompt_done_cb (GObject
*source_object
,
662 GAsyncResult
*result
,
665 RefreshData
*rd
= user_data
;
666 ENamedParameters
*credentials
= NULL
;
667 ESource
*source
= NULL
;
668 GError
*local_error
= NULL
;
670 g_return_if_fail (rd
!= NULL
);
671 g_return_if_fail (E_IS_CREDENTIALS_PROMPTER (source_object
));
673 if (!e_credentials_prompter_prompt_finish (E_CREDENTIALS_PROMPTER (source_object
), result
,
674 &source
, &credentials
, &local_error
)) {
675 g_simple_async_result_take_error (rd
->simple
, local_error
);
677 g_simple_async_result_complete (rd
->simple
);
678 refresh_data_free (rd
);
680 e_named_parameters_free (rd
->credentials
);
681 rd
->credentials
= credentials
;
684 if (e_source_has_extension (source
, E_SOURCE_EXTENSION_AUTHENTICATION
) &&
685 rd
->credentials
&& e_named_parameters_exists (rd
->credentials
, E_SOURCE_CREDENTIAL_USERNAME
)) {
686 ESourceAuthentication
*auth_extension
;
688 auth_extension
= e_source_get_extension (source
, E_SOURCE_EXTENSION_AUTHENTICATION
);
689 e_source_authentication_set_user (auth_extension
, e_named_parameters_get (rd
->credentials
, E_SOURCE_CREDENTIAL_USERNAME
));
692 e_webdav_discover_sources_full (source
, rd
->base_url
, E_WEBDAV_DISCOVER_SUPPORTS_NONE
, rd
->credentials
,
693 rd
->registry
? (EWebDAVDiscoverRefSourceFunc
) e_source_registry_ref_source
: NULL
, rd
->registry
,
694 rd
->cancellable
, e_webdav_discover_content_refresh_done_cb
, rd
);
697 e_named_parameters_free (credentials
);
698 g_clear_object (&source
);
699 g_clear_error (&local_error
);
703 e_webdav_discover_content_refresh_done_cb (GObject
*source_object
,
704 GAsyncResult
*result
,
707 RefreshData
*rd
= user_data
;
709 gchar
*certificate_pem
= NULL
;
710 GTlsCertificateFlags certificate_errors
= 0;
711 GSList
*discovered_sources
= NULL
;
712 GSList
*calendar_user_addresses
= NULL
;
713 GError
*local_error
= NULL
;
715 g_return_if_fail (E_IS_SOURCE (source_object
));
716 g_return_if_fail (rd
!= NULL
);
718 source
= E_SOURCE (source_object
);
720 if (!e_webdav_discover_sources_finish (source
, result
,
721 &certificate_pem
, &certificate_errors
, &discovered_sources
,
722 &calendar_user_addresses
, &local_error
)) {
723 if (!g_cancellable_is_cancelled (rd
->cancellable
) && certificate_pem
&&
724 g_error_matches (local_error
, SOUP_HTTP_ERROR
, SOUP_STATUS_SSL_FAILED
)) {
728 widget
= gtk_widget_get_toplevel (rd
->content
);
729 parent
= widget
? GTK_WINDOW (widget
) : NULL
;
731 e_trust_prompt_run_for_source (parent
, source
, certificate_pem
, certificate_errors
,
732 NULL
, FALSE
, rd
->cancellable
, e_webdav_discover_content_trust_prompt_done_cb
, rd
);
734 } else if (g_cancellable_is_cancelled (rd
->cancellable
) ||
735 (!g_error_matches (local_error
, G_IO_ERROR
, G_IO_ERROR_PERMISSION_DENIED
) &&
736 !g_error_matches (local_error
, G_IO_ERROR
, G_IO_ERROR_NOT_FOUND
) &&
737 !g_error_matches (local_error
, SOUP_HTTP_ERROR
, SOUP_STATUS_UNAUTHORIZED
) &&
738 !g_error_matches (local_error
, SOUP_HTTP_ERROR
, SOUP_STATUS_FORBIDDEN
))) {
739 g_simple_async_result_take_error (rd
->simple
, local_error
);
741 g_simple_async_result_complete (rd
->simple
);
743 EWebDAVDiscoverContentData
*data
;
745 data
= g_object_get_data (G_OBJECT (rd
->content
), WEBDAV_DISCOVER_CONTENT_DATA_KEY
);
746 g_return_if_fail (data
!= NULL
);
748 e_credentials_prompter_prompt (data
->credentials_prompter
, source
,
749 local_error
? local_error
->message
: NULL
,
750 rd
->credentials
? E_CREDENTIALS_PROMPTER_PROMPT_FLAG_NONE
:
751 E_CREDENTIALS_PROMPTER_PROMPT_FLAG_ALLOW_STORED_CREDENTIALS
,
752 e_webdav_discover_content_credentials_prompt_done_cb
, rd
);
756 EWebDAVDiscoverContentData
*data
;
758 data
= g_object_get_data (G_OBJECT (rd
->content
), WEBDAV_DISCOVER_CONTENT_DATA_KEY
);
759 g_warn_if_fail (data
!= NULL
);
762 e_webdav_discover_content_fill_discovered_sources (data
->sources_tree_view
,
763 data
->supports_filter
, discovered_sources
);
764 e_webdav_discover_content_fill_calendar_emails (data
->email_addresses_combo
,
765 calendar_user_addresses
);
768 g_simple_async_result_set_op_res_gboolean (rd
->simple
, TRUE
);
769 g_simple_async_result_complete (rd
->simple
);
772 g_free (certificate_pem
);
773 e_webdav_discover_free_discovered_sources (discovered_sources
);
774 g_slist_free_full (calendar_user_addresses
, g_free
);
775 refresh_data_free (rd
);
776 g_clear_error (&local_error
);
780 e_webdav_discover_info_bar_response_cb (GtkInfoBar
*info_bar
,
784 if (response_id
== GTK_RESPONSE_CANCEL
) {
785 g_return_if_fail (rd
!= NULL
);
786 g_return_if_fail (rd
->cancellable
!= NULL
);
788 g_cancellable_cancel (rd
->cancellable
);
793 * e_webdav_discover_content_refresh:
794 * @content: a WebDAV discovery content, created by e_webdav_discover_content_new()
795 * @display_name: (allow-none): optional display name to use for scratch sources
796 * @cancellable: (allow-none): optional #GCancellable object, or %NULL
797 * @callback: (scope async): a #GAsyncReadyCallback to call when the request
799 * @user_data: (closure): data to pass to the callback function
801 * Asynchronously starts refresh of the @content. This means to access the server
802 * and search it for available sources. The @content shows a feedback and a Cancel
803 * button during the operation.
805 * The @display_name is used only if the @content wasn't created with an #ESource and
806 * it's shown in the password prompts, if there are required any.
808 * When the operation is finished, @callback will be called. You can then
809 * call e_webdav_discover_content_refresh_finish() to get the result of the operation.
814 e_webdav_discover_content_refresh (GtkWidget
*content
,
815 const gchar
*display_name
,
816 GCancellable
*cancellable
,
817 GAsyncReadyCallback callback
,
820 EWebDAVDiscoverContentData
*data
;
826 g_return_if_fail (GTK_IS_GRID (content
));
828 data
= g_object_get_data (G_OBJECT (content
), WEBDAV_DISCOVER_CONTENT_DATA_KEY
);
829 g_return_if_fail (data
!= NULL
);
830 g_return_if_fail (data
->base_url
!= NULL
);
832 soup_uri
= soup_uri_new (data
->base_url
);
834 GSimpleAsyncResult
*simple
;
836 simple
= g_simple_async_result_new (G_OBJECT (content
), callback
, user_data
, e_webdav_discover_content_refresh
);
837 g_simple_async_result_set_error (simple
, G_IO_ERROR
, G_IO_ERROR_INVALID_ARGUMENT
,
839 g_simple_async_result_complete_in_idle (simple
);
840 g_object_unref (simple
);
845 rd
= g_new0 (RefreshData
, 1);
846 rd
->content
= g_object_ref (content
);
847 rd
->cancellable
= cancellable
? g_object_ref (cancellable
) : g_cancellable_new ();
848 rd
->simple
= g_simple_async_result_new (G_OBJECT (content
), callback
, user_data
, e_webdav_discover_content_refresh
);
849 rd
->base_url
= g_strdup (data
->base_url
);
850 rd
->credentials
= NULL
;
851 rd
->registry
= e_credentials_prompter_get_registry (data
->credentials_prompter
);
854 g_object_ref (rd
->registry
);
857 source
= g_object_ref (data
->source
);
859 ESourceWebdav
*webdav_extension
;
860 ESourceAuthentication
*auth_extension
;
862 source
= e_source_new_with_uid (data
->base_url
, NULL
, NULL
);
863 g_return_if_fail (source
!= NULL
);
865 webdav_extension
= e_source_get_extension (source
, E_SOURCE_EXTENSION_WEBDAV_BACKEND
);
866 auth_extension
= e_source_get_extension (source
, E_SOURCE_EXTENSION_AUTHENTICATION
);
868 if (display_name
&& *display_name
)
869 e_source_set_display_name (source
, display_name
);
870 e_source_webdav_set_soup_uri (webdav_extension
, soup_uri
);
871 e_source_authentication_set_host (auth_extension
, soup_uri_get_host (soup_uri
));
872 e_source_authentication_set_port (auth_extension
, soup_uri_get_port (soup_uri
));
873 e_source_authentication_set_user (auth_extension
, soup_uri_get_user (soup_uri
));
876 gtk_list_store_clear (GTK_LIST_STORE (gtk_tree_view_get_model (data
->sources_tree_view
)));
877 if (data
->email_addresses_combo
)
878 gtk_combo_box_text_remove_all (GTK_COMBO_BOX_TEXT (data
->email_addresses_combo
));
881 gtk_widget_destroy (GTK_WIDGET (data
->info_bar
));
883 data
->info_bar
= GTK_INFO_BAR (gtk_info_bar_new_with_buttons (_("Cancel"), GTK_RESPONSE_CANCEL
, NULL
));
884 gtk_info_bar_set_message_type (data
->info_bar
, GTK_MESSAGE_INFO
);
885 gtk_info_bar_set_show_close_button (data
->info_bar
, FALSE
);
886 label
= gtk_label_new (_("Searching server sources..."));
887 gtk_container_add (GTK_CONTAINER (gtk_info_bar_get_content_area (data
->info_bar
)), label
);
888 gtk_widget_show (label
);
889 gtk_widget_show (GTK_WIDGET (data
->info_bar
));
891 g_signal_connect (data
->info_bar
, "response", G_CALLBACK (e_webdav_discover_info_bar_response_cb
), rd
);
893 gtk_widget_set_sensitive (GTK_WIDGET (data
->sources_tree_view
), FALSE
);
894 if (data
->email_addresses_combo
)
895 gtk_widget_set_sensitive (GTK_WIDGET (data
->email_addresses_combo
), FALSE
);
897 gtk_grid_attach (GTK_GRID (content
), GTK_WIDGET (data
->info_bar
), 0, 2, 1, 1);
899 e_webdav_discover_sources_full (source
, rd
->base_url
, E_WEBDAV_DISCOVER_SUPPORTS_NONE
, rd
->credentials
,
900 rd
->registry
? (EWebDAVDiscoverRefSourceFunc
) e_source_registry_ref_source
: NULL
, rd
->registry
,
901 rd
->cancellable
, e_webdav_discover_content_refresh_done_cb
, rd
);
903 g_object_unref (source
);
904 soup_uri_free (soup_uri
);
908 * e_webdav_discover_content_refresh_finish:
909 * @content: a WebDAV discovery content, created by e_webdav_discover_content_new()
910 * @result: a #GAsyncResult
911 * @error: (allow-none): return location for a #GError, or %NULL
913 * Finishes the operation started with e_webdav_discover_content_refresh(). If an
914 * error occurred, the function will set @error and return %FALSE. There is
915 * available e_webdav_discover_content_show_error() for convenience, which
916 * shows the error within @content and takes care of it when refreshing
919 * Returns: %TRUE on success, %FALSE on failure
924 e_webdav_discover_content_refresh_finish (GtkWidget
*content
,
925 GAsyncResult
*result
,
928 EWebDAVDiscoverContentData
*data
;
929 GSimpleAsyncResult
*simple
;
931 g_return_val_if_fail (GTK_IS_GRID (content
), FALSE
);
933 data
= g_object_get_data (G_OBJECT (content
), WEBDAV_DISCOVER_CONTENT_DATA_KEY
);
934 g_return_val_if_fail (data
!= NULL
, FALSE
);
935 g_return_val_if_fail (g_simple_async_result_is_valid (
936 result
, G_OBJECT (content
), e_webdav_discover_content_refresh
), FALSE
);
938 simple
= G_SIMPLE_ASYNC_RESULT (result
);
940 if (g_simple_async_result_propagate_error (simple
, error
))
943 return g_simple_async_result_get_op_res_gboolean (simple
);
947 e_webdav_discover_info_bar_error_response_cb (GtkInfoBar
*info_bar
,
951 EWebDAVDiscoverContentData
*data
;
953 g_return_if_fail (GTK_IS_GRID (content
));
955 data
= g_object_get_data (G_OBJECT (content
), WEBDAV_DISCOVER_CONTENT_DATA_KEY
);
956 g_return_if_fail (data
!= NULL
);
958 if (data
->info_bar
== info_bar
) {
959 gtk_widget_destroy (GTK_WIDGET (data
->info_bar
));
960 data
->info_bar
= NULL
;
965 * e_webdav_discover_content_show_error:
966 * @content: a WebDAV discovery content, created by e_webdav_discover_content_new()
967 * @error: (allow-none): a #GError to show in the UI, or %NULL
969 * Shows the @error within @content, unless it's a #G_IO_ERROR_CANCELLED, or %NULL,
970 * which are safely ignored. The advantage of this function is that the error
971 * message is removed when the refresh operation is started.
976 e_webdav_discover_content_show_error (GtkWidget
*content
,
979 EWebDAVDiscoverContentData
*data
;
982 g_return_if_fail (GTK_IS_GRID (content
));
984 data
= g_object_get_data (G_OBJECT (content
), WEBDAV_DISCOVER_CONTENT_DATA_KEY
);
985 g_return_if_fail (data
!= NULL
);
987 if (data
->info_bar
) {
988 gtk_widget_destroy (GTK_WIDGET (data
->info_bar
));
989 data
->info_bar
= NULL
;
992 if (!error
|| g_error_matches (error
, G_IO_ERROR
, G_IO_ERROR_CANCELLED
))
995 data
->info_bar
= GTK_INFO_BAR (gtk_info_bar_new ());
996 gtk_info_bar_set_message_type (data
->info_bar
, GTK_MESSAGE_ERROR
);
997 gtk_info_bar_set_show_close_button (data
->info_bar
, TRUE
);
999 label
= gtk_label_new (error
->message
);
1000 gtk_label_set_max_width_chars (GTK_LABEL (label
), 120);
1001 gtk_label_set_line_wrap (GTK_LABEL (label
), TRUE
);
1002 gtk_label_set_selectable (GTK_LABEL (label
), TRUE
);
1003 gtk_container_add (GTK_CONTAINER (gtk_info_bar_get_content_area (data
->info_bar
)), label
);
1004 gtk_widget_show (label
);
1005 gtk_widget_show (GTK_WIDGET (data
->info_bar
));
1007 g_signal_connect (data
->info_bar
, "response", G_CALLBACK (e_webdav_discover_info_bar_error_response_cb
), content
);
1009 gtk_grid_attach (GTK_GRID (content
), GTK_WIDGET (data
->info_bar
), 0, 2, 1, 1);
1013 e_webdav_discover_content_dialog_refresh_done_cb (GObject
*source_object
,
1014 GAsyncResult
*result
,
1017 GError
*local_error
= NULL
;
1019 if (!e_webdav_discover_content_refresh_finish (GTK_WIDGET (source_object
), result
, &local_error
)) {
1020 e_webdav_discover_content_show_error (GTK_WIDGET (source_object
), local_error
);
1023 g_clear_error (&local_error
);
1027 e_webdav_discover_content_selection_changed_cb (GtkTreeSelection
*selection
,
1030 g_return_if_fail (GTK_IS_TREE_SELECTION (selection
));
1031 g_return_if_fail (GTK_IS_DIALOG (dialog
));
1033 gtk_dialog_set_response_sensitive (dialog
, GTK_RESPONSE_ACCEPT
,
1034 gtk_tree_selection_count_selected_rows (selection
) > 0);
1038 * e_webdav_discover_dialog_new:
1039 * @parent: a #GtkWindow parent for the dialog
1040 * @title: title of the window
1041 * @credentials_prompter: an #ECredentialsPrompter to use to ask for credentials
1042 * @source: an #ESource to use for authentication
1043 * @base_url: (allow-none): optional base URL to use for discovery, or %NULL
1044 * @supports_filter: a bit-or of #EWebDAVDiscoverSupports, a filter to limit what source
1045 * types will be shown in the dialog content; use %E_WEBDAV_DISCOVER_SUPPORTS_NONE
1048 * Creates a new #GtkDialog which has as its content a WebDAV discovery widget,
1049 * created with e_webdav_discover_content_new(). This dialog can be shown to a user
1050 * and when its final response is %GTK_RESPONSE_ACCEPT, then the inner content
1051 * can be asked for currently selected source(s).
1053 * Returns: (transfer full): a newly created #GtkDialog, which should be freed
1054 * with gtk_widget_destroy(), when no longer needed.
1059 e_webdav_discover_dialog_new (GtkWindow
*parent
,
1061 ECredentialsPrompter
*credentials_prompter
,
1063 const gchar
*base_url
,
1064 guint supports_filter
)
1066 GtkWidget
*dialog
, *container
, *widget
;
1067 GtkTreeSelection
*selection
;
1069 dialog
= gtk_dialog_new_with_buttons (title
, parent
, GTK_DIALOG_DESTROY_WITH_PARENT
,
1070 _("_Cancel"), GTK_RESPONSE_REJECT
,
1071 _("_OK"), GTK_RESPONSE_ACCEPT
,
1074 widget
= e_webdav_discover_content_new (credentials_prompter
, source
, base_url
, supports_filter
);
1076 g_object_set (G_OBJECT (widget
),
1079 "halign", GTK_ALIGN_FILL
,
1080 "valign", GTK_ALIGN_FILL
,
1083 container
= gtk_dialog_get_content_area (GTK_DIALOG (dialog
));
1085 gtk_container_add (GTK_CONTAINER (container
), widget
);
1087 g_object_set_data (G_OBJECT (dialog
), WEBDAV_DISCOVER_CONTENT_KEY
, widget
);
1089 gtk_window_set_default_size (GTK_WINDOW (dialog
), 400, 400);
1091 selection
= e_webdav_discover_content_get_tree_selection (widget
);
1092 g_signal_connect (selection
, "changed", G_CALLBACK (e_webdav_discover_content_selection_changed_cb
), dialog
);
1093 e_webdav_discover_content_selection_changed_cb (selection
, GTK_DIALOG (dialog
));
1095 return GTK_DIALOG (dialog
);
1099 * e_webdav_discover_dialog_get_content:
1100 * @dialog: a #GtkDialog returned by e_webdav_discover_dialog_new()
1102 * Returns inner WebDAV discovery content, which can be further manipulated.
1104 * Returns: (transfer none): inner WebDAV discovery content
1109 e_webdav_discover_dialog_get_content (GtkDialog
*dialog
)
1113 g_return_val_if_fail (GTK_IS_DIALOG (dialog
), NULL
);
1115 content
= g_object_get_data (G_OBJECT (dialog
), WEBDAV_DISCOVER_CONTENT_KEY
);
1116 g_return_val_if_fail (content
!= NULL
, NULL
);
1122 * e_webdav_discover_dialog_refresh:
1123 * @dialog: a #GtkDialog returned by e_webdav_discover_dialog_new()
1125 * Invokes refresh of the inner content of the WebDAV discovery dialog.
1130 e_webdav_discover_dialog_refresh (GtkDialog
*dialog
)
1134 g_return_if_fail (GTK_IS_DIALOG (dialog
));
1136 content
= g_object_get_data (G_OBJECT (dialog
), WEBDAV_DISCOVER_CONTENT_KEY
);
1137 g_return_if_fail (content
!= NULL
);
1139 e_webdav_discover_content_refresh (content
, gtk_window_get_title (GTK_WINDOW (dialog
)),
1140 NULL
, e_webdav_discover_content_dialog_refresh_done_cb
, NULL
);