1 /*
2 * evolution-cal-config-caldav.c
3 *
4 * This program 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 program is distributed in the hope that it will be useful, but
9 * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
10 * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
11 * for more details.
12 *
13 * You should have received a copy of the GNU Lesser General Public License
14 * along with this program; if not, see <http://www.gnu.org/licenses/>.
15 *
16 */
17
18 #include "evolution-config.h"
19
20 #include <glib/gi18n-lib.h>
21
22 #include <libebackend/libebackend.h>
23 #include <libedataserverui/libedataserverui.h>
24
25 #include <e-util/e-util.h>
26
27 typedef ESourceConfigBackend ECalConfigCalDAV;
28 typedef ESourceConfigBackendClass ECalConfigCalDAVClass;
29
30 typedef struct _Context Context;
31
32 struct _Context {
33 ESourceConfigBackend *backend; /* not referenced */
34 ESource *scratch_source; /* not referenced */
35
36 GtkWidget *url_entry;
37 GtkWidget *email_entry;
38 GtkWidget *find_button;
39 GtkWidget *auto_schedule_toggle;
40 };
41
42 /* Module Entry Points */
43 void e_module_load (GTypeModule *type_module);
44 void e_module_unload (GTypeModule *type_module);
45
46 /* Forward Declarations */
47 GType e_cal_config_caldav_get_type (void);
48
G_DEFINE_DYNAMIC_TYPE(ECalConfigCalDAV,e_cal_config_caldav,E_TYPE_SOURCE_CONFIG_BACKEND)49 G_DEFINE_DYNAMIC_TYPE (
50 ECalConfigCalDAV,
51 e_cal_config_caldav,
52 E_TYPE_SOURCE_CONFIG_BACKEND)
53
54 static Context *
55 cal_config_caldav_context_new (ESourceConfigBackend *backend,
56 ESource *scratch_source)
57 {
58 Context *context;
59
60 context = g_slice_new0 (Context);
61 context->backend = backend;
62 context->scratch_source = scratch_source;
63
64 return context;
65 }
66
67 static void
cal_config_caldav_context_free(Context * context)68 cal_config_caldav_context_free (Context *context)
69 {
70 g_clear_object (&context->url_entry);
71 g_clear_object (&context->email_entry);
72 g_clear_object (&context->find_button);
73 g_clear_object (&context->auto_schedule_toggle);
74
75 g_slice_free (Context, context);
76 }
77
78 static GtkWindow *
caldav_config_get_dialog_parent_cb(ECredentialsPrompter * prompter,GtkWindow * dialog)79 caldav_config_get_dialog_parent_cb (ECredentialsPrompter *prompter,
80 GtkWindow *dialog)
81 {
82 return dialog;
83 }
84
85 static void
cal_config_caldav_run_dialog(GtkButton * button,Context * context)86 cal_config_caldav_run_dialog (GtkButton *button,
87 Context *context)
88 {
89 ESourceConfig *config;
90 ESourceRegistry *registry;
91 ESourceWebdav *webdav_extension;
92 ECalClientSourceType source_type;
93 ECredentialsPrompter *prompter;
94 SoupURI *uri;
95 gchar *base_url;
96 GtkDialog *dialog;
97 gpointer parent;
98 gulong handler_id;
99 guint supports_filter = 0;
100 const gchar *title = NULL;
101
102 config = e_source_config_backend_get_config (context->backend);
103 registry = e_source_config_get_registry (config);
104
105 parent = gtk_widget_get_toplevel (GTK_WIDGET (config));
106 parent = gtk_widget_is_toplevel (parent) ? parent : NULL;
107 source_type = e_cal_source_config_get_source_type (E_CAL_SOURCE_CONFIG (config));
108
109 switch (source_type) {
110 case E_CAL_CLIENT_SOURCE_TYPE_EVENTS:
111 supports_filter = E_WEBDAV_DISCOVER_SUPPORTS_EVENTS;
112 title = _("Choose a Calendar");
113 break;
114 case E_CAL_CLIENT_SOURCE_TYPE_MEMOS:
115 supports_filter = E_WEBDAV_DISCOVER_SUPPORTS_MEMOS;
116 title = _("Choose a Memo List");
117 break;
118 case E_CAL_CLIENT_SOURCE_TYPE_TASKS:
119 supports_filter = E_WEBDAV_DISCOVER_SUPPORTS_TASKS;
120 title = _("Choose a Task List");
121 break;
122 default:
123 g_return_if_reached ();
124 }
125
126 webdav_extension = e_source_get_extension (context->scratch_source, E_SOURCE_EXTENSION_WEBDAV_BACKEND);
127
128 uri = e_source_webdav_dup_soup_uri (webdav_extension);
129
130 prompter = e_credentials_prompter_new (registry);
131 e_credentials_prompter_set_auto_prompt (prompter, FALSE);
132 base_url = soup_uri_to_string (uri, FALSE);
133
134 dialog = e_webdav_discover_dialog_new (parent, title, prompter, context->scratch_source, base_url, supports_filter);
135
136 if (parent != NULL)
137 e_binding_bind_property (
138 parent, "icon-name",
139 dialog, "icon-name",
140 G_BINDING_SYNC_CREATE);
141
142 handler_id = g_signal_connect (prompter, "get-dialog-parent",
143 G_CALLBACK (caldav_config_get_dialog_parent_cb), dialog);
144
145 e_webdav_discover_dialog_refresh (dialog);
146
147 if (gtk_dialog_run (dialog) == GTK_RESPONSE_ACCEPT) {
148 gchar *href = NULL, *display_name = NULL, *color = NULL, *email;
149 guint supports = 0, order = 0;
150 GtkWidget *content;
151
152 content = e_webdav_discover_dialog_get_content (dialog);
153
154 if (e_webdav_discover_content_get_selected (content, 0, &href, &supports, &display_name, &color, &order)) {
155 soup_uri_free (uri);
156 uri = soup_uri_new (href);
157
158 if (uri) {
159 ESourceSelectable *selectable_extension;
160 const gchar *extension_name;
161
162 switch (source_type) {
163 case E_CAL_CLIENT_SOURCE_TYPE_EVENTS:
164 extension_name = E_SOURCE_EXTENSION_CALENDAR;
165 break;
166 case E_CAL_CLIENT_SOURCE_TYPE_MEMOS:
167 extension_name = E_SOURCE_EXTENSION_MEMO_LIST;
168 break;
169 case E_CAL_CLIENT_SOURCE_TYPE_TASKS:
170 extension_name = E_SOURCE_EXTENSION_TASK_LIST;
171 break;
172 default:
173 g_return_if_reached ();
174 }
175
176 selectable_extension = e_source_get_extension (context->scratch_source, extension_name);
177
178 e_source_set_display_name (context->scratch_source, display_name);
179
180 e_source_webdav_set_display_name (webdav_extension, display_name);
181 e_source_webdav_set_soup_uri (webdav_extension, uri);
182 e_source_webdav_set_order (webdav_extension, order);
183
184 if (source_type != E_CAL_CLIENT_SOURCE_TYPE_MEMOS)
185 e_source_webdav_set_calendar_auto_schedule (webdav_extension, (supports & E_WEBDAV_DISCOVER_SUPPORTS_CALENDAR_AUTO_SCHEDULE) != 0);
186
187 if (color && *color)
188 e_source_selectable_set_color (selectable_extension, color);
189
190 e_source_selectable_set_order (selectable_extension, order);
191 }
192
193 g_free (href);
194 g_free (display_name);
195 g_free (color);
196
197 href = NULL;
198 display_name = NULL;
199 color = NULL;
200 }
201
202 email = e_webdav_discover_content_get_user_address (content);
203 if (email && *email)
204 e_source_webdav_set_email_address (webdav_extension, email);
205 g_free (email);
206 }
207
208 g_signal_handler_disconnect (prompter, handler_id);
209
210 gtk_widget_destroy (GTK_WIDGET (dialog));
211
212 g_object_unref (prompter);
213 if (uri)
214 soup_uri_free (uri);
215 g_free (base_url);
216 }
217
218 static gboolean
cal_config_caldav_uri_to_text(GBinding * binding,const GValue * source_value,GValue * target_value,gpointer user_data)219 cal_config_caldav_uri_to_text (GBinding *binding,
220 const GValue *source_value,
221 GValue *target_value,
222 gpointer user_data)
223 {
224 SoupURI *soup_uri;
225 gchar *text;
226
227 soup_uri = g_value_get_boxed (source_value);
228 soup_uri_set_user (soup_uri, NULL);
229
230 if (soup_uri_get_host (soup_uri)) {
231 text = soup_uri_to_string (soup_uri, FALSE);
232 } else {
233 GObject *target;
234
235 text = NULL;
236 target = g_binding_get_target (binding);
237 g_object_get (target, g_binding_get_target_property (binding), &text, NULL);
238
239 if (!text || !*text) {
240 g_free (text);
241 text = soup_uri_to_string (soup_uri, FALSE);
242 }
243 }
244
245 g_value_take_string (target_value, text);
246
247 return TRUE;
248 }
249
250 static gboolean
cal_config_caldav_text_to_uri(GBinding * binding,const GValue * source_value,GValue * target_value,gpointer user_data)251 cal_config_caldav_text_to_uri (GBinding *binding,
252 const GValue *source_value,
253 GValue *target_value,
254 gpointer user_data)
255 {
256 ESource *source;
257 SoupURI *soup_uri;
258 ESourceAuthentication *extension;
259 const gchar *extension_name;
260 const gchar *text;
261 const gchar *user;
262
263 text = g_value_get_string (source_value);
264 soup_uri = soup_uri_new (text);
265
266 if (!soup_uri)
267 soup_uri = soup_uri_new ("http://");
268
269 source = E_SOURCE (user_data);
270 extension_name = E_SOURCE_EXTENSION_AUTHENTICATION;
271 extension = e_source_get_extension (source, extension_name);
272 user = e_source_authentication_get_user (extension);
273
274 soup_uri_set_user (soup_uri, user);
275
276 g_value_take_boxed (target_value, soup_uri);
277
278 return TRUE;
279 }
280
281 static void
cal_config_caldav_insert_widgets(ESourceConfigBackend * backend,ESource * scratch_source)282 cal_config_caldav_insert_widgets (ESourceConfigBackend *backend,
283 ESource *scratch_source)
284 {
285 ESourceConfig *config;
286 ESource *collection_source;
287 ESourceExtension *extension;
288 ECalClientSourceType source_type;
289 GtkWidget *widget;
290 Context *context;
291 const gchar *extension_name;
292 const gchar *label;
293 const gchar *uid;
294
295 config = e_source_config_backend_get_config (backend);
296 collection_source = e_source_config_get_collection_source (config);
297
298 uid = e_source_get_uid (scratch_source);
299 context = cal_config_caldav_context_new (backend, scratch_source);
300
301 g_object_set_data_full (
302 G_OBJECT (backend), uid, context,
303 (GDestroyNotify) cal_config_caldav_context_free);
304
305 if (collection_source) {
306 widget = gtk_label_new ("");
307 g_object_set (G_OBJECT (widget),
308 "ellipsize", PANGO_ELLIPSIZE_MIDDLE,
309 "selectable", TRUE,
310 "xalign", 0.0f,
311 NULL);
312 e_source_config_insert_widget (config, scratch_source, _("URL:"), widget);
313 gtk_widget_show (widget);
314
315 extension = e_source_get_extension (scratch_source, E_SOURCE_EXTENSION_WEBDAV_BACKEND);
316
317 e_binding_bind_property_full (
318 extension, "soup-uri",
319 widget, "label",
320 G_BINDING_SYNC_CREATE,
321 cal_config_caldav_uri_to_text,
322 NULL,
323 g_object_ref (scratch_source),
324 (GDestroyNotify) g_object_unref);
325
326 e_binding_bind_property (
327 widget, "label",
328 widget, "tooltip-text",
329 G_BINDING_SYNC_CREATE);
330 } else {
331 widget = gtk_entry_new ();
332 e_source_config_insert_widget (
333 config, scratch_source, _("URL:"), widget);
334 context->url_entry = g_object_ref (widget);
335 gtk_widget_show (widget);
336 }
337
338 e_source_config_add_secure_connection_for_webdav (
339 config, scratch_source);
340
341 source_type = e_cal_source_config_get_source_type (E_CAL_SOURCE_CONFIG (config));
342
343 if (!collection_source) {
344 e_source_config_add_user_entry (config, scratch_source);
345
346 switch (source_type) {
347 case E_CAL_CLIENT_SOURCE_TYPE_EVENTS:
348 label = _("Find Calendars");
349 break;
350 case E_CAL_CLIENT_SOURCE_TYPE_MEMOS:
351 label = _("Find Memo Lists");
352 break;
353 case E_CAL_CLIENT_SOURCE_TYPE_TASKS:
354 label = _("Find Task Lists");
355 break;
356 default:
357 g_return_if_reached ();
358 }
359
360 widget = gtk_button_new_with_label (label);
361 e_source_config_insert_widget (
362 config, scratch_source, NULL, widget);
363 context->find_button = g_object_ref (widget);
364 gtk_widget_show (widget);
365
366 g_signal_connect (
367 widget, "clicked",
368 G_CALLBACK (cal_config_caldav_run_dialog), context);
369 }
370
371 widget = gtk_entry_new ();
372 e_source_config_insert_widget (
373 config, scratch_source, _("Email:"), widget);
374 context->email_entry = g_object_ref (widget);
375 gtk_widget_show (widget);
376
377 if (source_type != E_CAL_CLIENT_SOURCE_TYPE_MEMOS) {
378 widget = gtk_check_button_new_with_label (
379 _("Server handles meeting invitations"));
380 e_source_config_insert_widget (
381 config, scratch_source, NULL, widget);
382 context->auto_schedule_toggle = g_object_ref (widget);
383 gtk_widget_show (widget);
384 }
385
386 e_source_config_add_refresh_interval (config, scratch_source);
387
388 extension_name = E_SOURCE_EXTENSION_WEBDAV_BACKEND;
389 extension = e_source_get_extension (scratch_source, extension_name);
390
391 if (context->auto_schedule_toggle) {
392 e_binding_bind_property (
393 extension, "calendar-auto-schedule",
394 context->auto_schedule_toggle, "active",
395 G_BINDING_BIDIRECTIONAL |
396 G_BINDING_SYNC_CREATE);
397 }
398
399 e_binding_bind_object_text_property (
400 extension, "email-address",
401 context->email_entry, "text",
402 G_BINDING_BIDIRECTIONAL |
403 G_BINDING_SYNC_CREATE);
404
405 if (context->url_entry) {
406 e_binding_bind_property_full (
407 extension, "soup-uri",
408 context->url_entry, "text",
409 G_BINDING_BIDIRECTIONAL |
410 G_BINDING_SYNC_CREATE,
411 cal_config_caldav_uri_to_text,
412 cal_config_caldav_text_to_uri,
413 g_object_ref (scratch_source),
414 (GDestroyNotify) g_object_unref);
415 }
416 }
417
418 static gboolean
cal_config_caldav_check_complete(ESourceConfigBackend * backend,ESource * scratch_source)419 cal_config_caldav_check_complete (ESourceConfigBackend *backend,
420 ESource *scratch_source)
421 {
422 Context *context;
423 const gchar *uid;
424 const gchar *uri_string;
425 SoupURI *soup_uri;
426 gboolean complete;
427
428 uid = e_source_get_uid (scratch_source);
429 context = g_object_get_data (G_OBJECT (backend), uid);
430 g_return_val_if_fail (context != NULL, FALSE);
431
432 if (!context->url_entry)
433 return TRUE;
434
435 uri_string = gtk_entry_get_text (GTK_ENTRY (context->url_entry));
436 soup_uri = soup_uri_new (uri_string);
437
438 if (soup_uri) {
439 if (g_strcmp0 (soup_uri_get_scheme (soup_uri), "caldav") == 0)
440 soup_uri_set_scheme (soup_uri, SOUP_URI_SCHEME_HTTP);
441
442 complete = soup_uri_get_host (soup_uri) && SOUP_URI_VALID_FOR_HTTP (soup_uri);
443 } else {
444 complete = FALSE;
445 }
446
447 if (soup_uri != NULL)
448 soup_uri_free (soup_uri);
449
450 gtk_widget_set_sensitive (context->find_button, complete);
451
452 e_util_set_entry_issue_hint (context->url_entry, complete ? NULL : _("URL is not a valid http:// nor https:// URL"));
453
454 return complete;
455 }
456
457 static void
e_cal_config_caldav_class_init(ESourceConfigBackendClass * class)458 e_cal_config_caldav_class_init (ESourceConfigBackendClass *class)
459 {
460 EExtensionClass *extension_class;
461
462 extension_class = E_EXTENSION_CLASS (class);
463 extension_class->extensible_type = E_TYPE_CAL_SOURCE_CONFIG;
464
465 class->parent_uid = "caldav-stub";
466 class->backend_name = "caldav";
467 class->insert_widgets = cal_config_caldav_insert_widgets;
468 class->check_complete = cal_config_caldav_check_complete;
469 }
470
471 static void
e_cal_config_caldav_class_finalize(ESourceConfigBackendClass * class)472 e_cal_config_caldav_class_finalize (ESourceConfigBackendClass *class)
473 {
474 }
475
476 static void
e_cal_config_caldav_init(ESourceConfigBackend * backend)477 e_cal_config_caldav_init (ESourceConfigBackend *backend)
478 {
479 }
480
481 G_MODULE_EXPORT void
e_module_load(GTypeModule * type_module)482 e_module_load (GTypeModule *type_module)
483 {
484 e_cal_config_caldav_register_type (type_module);
485 }
486
487 G_MODULE_EXPORT void
e_module_unload(GTypeModule * type_module)488 e_module_unload (GTypeModule *type_module)
489 {
490 }
491