1 /* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
2 /*
3  * SPDX-FileCopyrightText: (C) 2012 Red Hat, Inc. (www.redhat.com)
4  * SPDX-License-Identifier: LGPL-2.1-or-later
5  */
6 
7 #include "evolution-ews-config.h"
8 
9 #include <string.h>
10 #include <unistd.h>
11 
12 #include <gtk/gtk.h>
13 #include <glib/gi18n-lib.h>
14 
15 #include <e-util/e-util.h>
16 
17 #include "common/camel-ews-settings.h"
18 #include "common/e-ews-connection.h"
19 #include "common/e-ews-connection-utils.h"
20 #include "common/e-ews-oof-settings.h"
21 
22 #include "e-ews-config-utils.h"
23 
24 #include "e-mail-config-ews-ooo-page.h"
25 
26 typedef struct _AsyncContext AsyncContext;
27 
28 struct _EMailConfigEwsOooPagePrivate {
29 	ESourceRegistry *registry;
30 	ESource *account_source;
31 	ESource *identity_source;
32 	ESource *collection_source;
33 
34 	/* The try_password() method deposits results here.
35 	 * This avoids calling GTK+ functions from multiple threads. */
36 	EEwsOofSettings *oof_settings;
37 	GMutex oof_settings_lock;
38 
39 	GCancellable *refresh_cancellable;
40 
41 	/* to not save unchanged state */
42 	gboolean changed;
43 
44 	GtkWidget *enabled_radio_button;	/* not referenced */
45 	GtkWidget *disabled_radio_button;	/* not referenced */
46 	GtkWidget *scheduled_radio_button;	/* not referenced */
47 	GtkWidget *start_time;			/* not referenced */
48 	GtkWidget *end_time;			/* not referenced */
49 	GtkWidget *external_audience;		/* not referenced */
50 	GtkTextBuffer *internal_reply;		/* not referenced */
51 	GtkTextBuffer *external_reply;		/* not referenced */
52 };
53 
54 struct _AsyncContext {
55 	EMailConfigEwsOooPage *page;
56 	EActivity *activity;
57 	ESource *source;
58 	GObject *settings;
59 };
60 
61 enum {
62 	PROP_0,
63 	PROP_ACCOUNT_SOURCE,
64 	PROP_COLLECTION_SOURCE,
65 	PROP_IDENTITY_SOURCE,
66 	PROP_REGISTRY
67 };
68 
69 /* Forward Declarations */
70 static void	e_mail_config_ews_ooo_page_interface_init
71 				(EMailConfigPageInterface *iface);
72 
73 G_DEFINE_DYNAMIC_TYPE_EXTENDED (EMailConfigEwsOooPage, e_mail_config_ews_ooo_page, E_TYPE_MAIL_CONFIG_ACTIVITY_PAGE, 0,
74 	G_ADD_PRIVATE_DYNAMIC (EMailConfigEwsOooPage)
75 	G_IMPLEMENT_INTERFACE_DYNAMIC (E_TYPE_MAIL_CONFIG_PAGE, e_mail_config_ews_ooo_page_interface_init))
76 
77 static void
async_context_free(gpointer ptr)78 async_context_free (gpointer ptr)
79 {
80 	AsyncContext *async_context = ptr;
81 
82 	if (!async_context)
83 		return;
84 
85 	if (async_context->settings)
86 		g_object_thaw_notify (async_context->settings);
87 
88 	g_clear_object (&async_context->page);
89 	g_clear_object (&async_context->activity);
90 	g_clear_object (&async_context->source);
91 	g_clear_object (&async_context->settings);
92 
93 	g_slice_free (AsyncContext, async_context);
94 }
95 
96 static CamelSettings *
mail_config_ews_ooo_page_get_settings(EMailConfigEwsOooPage * page)97 mail_config_ews_ooo_page_get_settings (EMailConfigEwsOooPage *page)
98 {
99 	ESource *source;
100 	ESourceCamel *extension;
101 	const gchar *extension_name;
102 
103 	source = e_mail_config_ews_ooo_page_get_collection_source (page);
104 
105 	extension_name = e_source_camel_get_extension_name ("ews");
106 	extension = e_source_get_extension (source, extension_name);
107 
108 	return e_source_camel_get_settings (extension);
109 }
110 
111 static const gchar *
mail_config_ews_ooo_page_get_mailbox(EMailConfigEwsOooPage * page)112 mail_config_ews_ooo_page_get_mailbox (EMailConfigEwsOooPage *page)
113 {
114 	ESourceRegistry *registry;
115 	ESource *collection_source;
116 	GList *list, *link;
117 	const gchar *collection_uid;
118 	const gchar *extension_name;
119 	const gchar *mailbox = NULL;
120 
121 	/* Find the mail identity source that belongs to
122 	 * our collection and return its email address. */
123 
124 	collection_source =
125 		e_mail_config_ews_ooo_page_get_collection_source (page);
126 	collection_uid = e_source_get_uid (collection_source);
127 
128 	extension_name = E_SOURCE_EXTENSION_MAIL_IDENTITY;
129 	registry = e_mail_config_ews_ooo_page_get_registry (page);
130 	list = e_source_registry_list_sources (registry, extension_name);
131 
132 	for (link = list; link != NULL; link = g_list_next (link)) {
133 		ESource *source = E_SOURCE (link->data);
134 		ESourceMailIdentity *extension;
135 		const gchar *parent_uid;
136 
137 		parent_uid = e_source_get_parent (source);
138 		if (g_strcmp0 (parent_uid, collection_uid) != 0)
139 			continue;
140 
141 		extension = e_source_get_extension (source, extension_name);
142 		mailbox = e_source_mail_identity_get_address (extension);
143 		break;
144 	}
145 
146 	g_list_free_full (list, g_object_unref);
147 
148 	return mailbox;
149 }
150 
151 static void
mail_config_ews_ooo_page_display_settings(EMailConfigEwsOooPage * page,EEwsOofSettings * oof_settings)152 mail_config_ews_ooo_page_display_settings (EMailConfigEwsOooPage *page,
153                                            EEwsOofSettings *oof_settings)
154 {
155 	GtkWidget *button;
156 	GDateTime *date_time;
157 
158 	switch (e_ews_oof_settings_get_state (oof_settings)) {
159 		default:
160 			/* fall through */
161 		case E_EWS_OOF_STATE_DISABLED:
162 			button = page->priv->disabled_radio_button;
163 			break;
164 		case E_EWS_OOF_STATE_ENABLED:
165 			button = page->priv->enabled_radio_button;
166 			break;
167 		case E_EWS_OOF_STATE_SCHEDULED:
168 			button = page->priv->scheduled_radio_button;
169 			break;
170 	}
171 
172 	gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (button), TRUE);
173 
174 	gtk_combo_box_set_active (
175 		GTK_COMBO_BOX (page->priv->external_audience),
176 		e_ews_oof_settings_get_external_audience (oof_settings));
177 
178 	date_time = e_ews_oof_settings_ref_start_time (oof_settings);
179 	e_date_edit_set_time (
180 		E_DATE_EDIT (page->priv->start_time),
181 		(time_t) g_date_time_to_unix (date_time));
182 	g_date_time_unref (date_time);
183 
184 	date_time = e_ews_oof_settings_ref_end_time (oof_settings);
185 	e_date_edit_set_time (
186 		E_DATE_EDIT (page->priv->end_time),
187 		(time_t) g_date_time_to_unix (date_time));
188 	g_date_time_unref (date_time);
189 
190 	gtk_text_buffer_set_text (
191 		page->priv->internal_reply,
192 		e_ews_oof_settings_get_internal_reply (oof_settings), -1);
193 
194 	gtk_text_buffer_set_text (
195 		page->priv->external_reply,
196 		e_ews_oof_settings_get_external_reply (oof_settings), -1);
197 }
198 
199 static void
mail_config_ews_ooo_page_set_account_source(EMailConfigEwsOooPage * page,ESource * account_source)200 mail_config_ews_ooo_page_set_account_source (EMailConfigEwsOooPage *page,
201                                              ESource *account_source)
202 {
203 	g_return_if_fail (E_IS_SOURCE (account_source));
204 	g_return_if_fail (page->priv->account_source == NULL);
205 
206 	page->priv->account_source = g_object_ref (account_source);
207 }
208 
209 static void
mail_config_ews_ooo_page_set_collection_source(EMailConfigEwsOooPage * page,ESource * collection_source)210 mail_config_ews_ooo_page_set_collection_source (EMailConfigEwsOooPage *page,
211                                                 ESource *collection_source)
212 {
213 	g_return_if_fail (E_IS_SOURCE (collection_source));
214 	g_return_if_fail (page->priv->collection_source == NULL);
215 
216 	page->priv->collection_source = g_object_ref (collection_source);
217 }
218 
219 static void
mail_config_ews_ooo_page_set_identity_source(EMailConfigEwsOooPage * page,ESource * identity_source)220 mail_config_ews_ooo_page_set_identity_source (EMailConfigEwsOooPage *page,
221                                               ESource *identity_source)
222 {
223 	g_return_if_fail (E_IS_SOURCE (identity_source));
224 	g_return_if_fail (page->priv->identity_source == NULL);
225 
226 	page->priv->identity_source = g_object_ref (identity_source);
227 }
228 
229 static void
mail_config_ews_ooo_page_set_registry(EMailConfigEwsOooPage * page,ESourceRegistry * registry)230 mail_config_ews_ooo_page_set_registry (EMailConfigEwsOooPage *page,
231                                        ESourceRegistry *registry)
232 {
233 	g_return_if_fail (E_IS_SOURCE_REGISTRY (registry));
234 	g_return_if_fail (page->priv->registry == NULL);
235 
236 	page->priv->registry = g_object_ref (registry);
237 }
238 
239 static void
mail_config_ews_ooo_page_set_property(GObject * object,guint property_id,const GValue * value,GParamSpec * pspec)240 mail_config_ews_ooo_page_set_property (GObject *object,
241                                        guint property_id,
242                                        const GValue *value,
243                                        GParamSpec *pspec)
244 {
245 	switch (property_id) {
246 		case PROP_ACCOUNT_SOURCE:
247 			mail_config_ews_ooo_page_set_account_source (
248 				E_MAIL_CONFIG_EWS_OOO_PAGE (object),
249 				g_value_get_object (value));
250 			return;
251 
252 		case PROP_COLLECTION_SOURCE:
253 			mail_config_ews_ooo_page_set_collection_source (
254 				E_MAIL_CONFIG_EWS_OOO_PAGE (object),
255 				g_value_get_object (value));
256 			return;
257 
258 		case PROP_IDENTITY_SOURCE:
259 			mail_config_ews_ooo_page_set_identity_source (
260 				E_MAIL_CONFIG_EWS_OOO_PAGE (object),
261 				g_value_get_object (value));
262 			return;
263 
264 		case PROP_REGISTRY:
265 			mail_config_ews_ooo_page_set_registry (
266 				E_MAIL_CONFIG_EWS_OOO_PAGE (object),
267 				g_value_get_object (value));
268 			return;
269 	}
270 
271 	G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
272 }
273 
274 static void
mail_config_ews_ooo_page_get_property(GObject * object,guint property_id,GValue * value,GParamSpec * pspec)275 mail_config_ews_ooo_page_get_property (GObject *object,
276                                        guint property_id,
277                                        GValue *value,
278                                        GParamSpec *pspec)
279 {
280 	switch (property_id) {
281 		case PROP_ACCOUNT_SOURCE:
282 			g_value_set_object (
283 				value,
284 				e_mail_config_ews_ooo_page_get_account_source (
285 				E_MAIL_CONFIG_EWS_OOO_PAGE (object)));
286 			return;
287 
288 		case PROP_COLLECTION_SOURCE:
289 			g_value_set_object (
290 				value,
291 				e_mail_config_ews_ooo_page_get_collection_source (
292 				E_MAIL_CONFIG_EWS_OOO_PAGE (object)));
293 			return;
294 
295 		case PROP_IDENTITY_SOURCE:
296 			g_value_set_object (
297 				value,
298 				e_mail_config_ews_ooo_page_get_identity_source (
299 				E_MAIL_CONFIG_EWS_OOO_PAGE (object)));
300 			return;
301 
302 		case PROP_REGISTRY:
303 			g_value_set_object (
304 				value,
305 				e_mail_config_ews_ooo_page_get_registry (
306 				E_MAIL_CONFIG_EWS_OOO_PAGE (object)));
307 			return;
308 	}
309 
310 	G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
311 }
312 
313 static void
mail_config_ews_ooo_page_dispose(GObject * object)314 mail_config_ews_ooo_page_dispose (GObject *object)
315 {
316 	EMailConfigEwsOooPage *ooo_page = E_MAIL_CONFIG_EWS_OOO_PAGE (object);
317 
318 	if (ooo_page->priv->refresh_cancellable) {
319 		g_cancellable_cancel (ooo_page->priv->refresh_cancellable);
320 		g_clear_object (&ooo_page->priv->refresh_cancellable);
321 	}
322 
323 	g_clear_object (&ooo_page->priv->registry);
324 	g_clear_object (&ooo_page->priv->account_source);
325 	g_clear_object (&ooo_page->priv->collection_source);
326 	g_clear_object (&ooo_page->priv->identity_source);
327 	g_clear_object (&ooo_page->priv->oof_settings);
328 
329 	/* Chain up to parent's dispose() method. */
330 	G_OBJECT_CLASS (e_mail_config_ews_ooo_page_parent_class)->dispose (object);
331 }
332 
333 static void
mail_config_ews_ooo_page_finalize(GObject * object)334 mail_config_ews_ooo_page_finalize (GObject *object)
335 {
336 	EMailConfigEwsOooPage *ooo_page = E_MAIL_CONFIG_EWS_OOO_PAGE (object);
337 
338 	g_mutex_clear (&ooo_page->priv->oof_settings_lock);
339 
340 	/* Chain up to parent's finalize() method. */
341 	G_OBJECT_CLASS (e_mail_config_ews_ooo_page_parent_class)->finalize (object);
342 }
343 
344 static void
mail_config_ews_ooo_page_constructed(GObject * object)345 mail_config_ews_ooo_page_constructed (GObject *object)
346 {
347 	EMailConfigEwsOooPage *page;
348 	GtkLabel *label;
349 	GtkWidget *grid;
350 	GtkWidget *widget;
351 	GtkWidget *container;
352 	GtkWidget *main_box;
353 	GtkSizeGroup *size_group;
354 	GtkTextBuffer *text_buffer;
355 	GSList *group = NULL;
356 	const gchar *text;
357 	gchar *markup;
358 
359 	page = E_MAIL_CONFIG_EWS_OOO_PAGE (object);
360 
361 	/* Chain up to parent's constructed() method. */
362 	G_OBJECT_CLASS (e_mail_config_ews_ooo_page_parent_class)->constructed (object);
363 
364 	main_box = e_mail_config_activity_page_get_internal_box (E_MAIL_CONFIG_ACTIVITY_PAGE (page));
365 	gtk_box_set_spacing (GTK_BOX (main_box), 12);
366 
367 	size_group = gtk_size_group_new (GTK_SIZE_GROUP_HORIZONTAL);
368 
369 	text = _("Out of Office");
370 	markup = g_markup_printf_escaped ("<b>%s</b>", text);
371 	widget = gtk_label_new (markup);
372 	gtk_label_set_use_markup (GTK_LABEL (widget), TRUE);
373 	gtk_misc_set_alignment (GTK_MISC (widget), 0.0, 0.5);
374 	gtk_box_pack_start (GTK_BOX (main_box), widget, FALSE, FALSE, 0);
375 	gtk_widget_show (widget);
376 	g_free (markup);
377 
378 	widget = gtk_box_new (GTK_ORIENTATION_VERTICAL, 6);
379 	gtk_widget_set_margin_left (widget, 12);
380 	gtk_box_pack_start (GTK_BOX (main_box), widget, FALSE, FALSE, 0);
381 	gtk_widget_show (widget);
382 
383 	container = widget;
384 
385 	text = _("The messages specified below will be automatically sent to "
386 		 "each internal and external person who sends a mail to you.");
387 	widget = gtk_label_new (text);
388 	gtk_label_set_width_chars (GTK_LABEL (widget), 20);
389 	gtk_label_set_max_width_chars (GTK_LABEL (widget), 80);
390 	gtk_label_set_line_wrap (GTK_LABEL (widget), TRUE);
391 	gtk_misc_set_alignment (GTK_MISC (widget), 0.0, 0.5);
392 	gtk_box_pack_start (GTK_BOX (container), widget, FALSE, FALSE, 0);
393 	gtk_widget_show (widget);
394 
395 	text = _("Do _not send Out of Office replies");
396 	widget = gtk_radio_button_new_with_mnemonic (group, text);
397 	gtk_box_pack_start (GTK_BOX (container), widget, FALSE, FALSE, 0);
398 	page->priv->disabled_radio_button = widget;  /* do not reference */
399 	gtk_widget_show (widget);
400 
401 	group = gtk_radio_button_get_group (GTK_RADIO_BUTTON (widget));
402 
403 	text = _("_Send Out of Office replies");
404 	widget = gtk_radio_button_new_with_mnemonic (group, text);
405 	gtk_box_pack_start (GTK_BOX (container), widget, FALSE, FALSE, 0);
406 	page->priv->enabled_radio_button = widget;  /* do not reference */
407 	gtk_widget_show (widget);
408 
409 	group = gtk_radio_button_get_group (GTK_RADIO_BUTTON (widget));
410 
411 	text = _("Send Out of Office replies only _during this time period:");
412 	widget = gtk_radio_button_new_with_mnemonic (group, text);
413 	gtk_box_pack_start (GTK_BOX (container), widget, FALSE, FALSE, 0);
414 	page->priv->scheduled_radio_button = widget;  /* do not reference */
415 	gtk_widget_show (widget);
416 
417 	widget = gtk_grid_new ();
418 	gtk_grid_set_row_spacing (GTK_GRID (widget), 6);
419 	gtk_grid_set_column_spacing (GTK_GRID (widget), 6);
420 	gtk_box_pack_start (GTK_BOX (main_box), widget, TRUE, TRUE, 0);
421 	gtk_widget_show (widget);
422 
423 	e_binding_bind_property (
424 		page->priv->disabled_radio_button, "active",
425 		widget, "sensitive",
426 		G_BINDING_SYNC_CREATE |
427 		G_BINDING_INVERT_BOOLEAN);
428 
429 	grid = widget;
430 
431 	widget = gtk_label_new_with_mnemonic (_("_From:"));
432 	gtk_widget_set_margin_left (widget, 12);
433 	gtk_misc_set_alignment (GTK_MISC (widget), 1.0, 0.5);
434 	gtk_grid_attach (GTK_GRID (grid), widget, 0, 1, 1, 1);
435 	gtk_size_group_add_widget (size_group, widget);
436 	gtk_widget_show (widget);
437 
438 	e_binding_bind_property (
439 		page->priv->scheduled_radio_button, "active",
440 		widget, "sensitive",
441 		G_BINDING_SYNC_CREATE);
442 
443 	label = GTK_LABEL (widget);
444 
445 	widget = e_date_edit_new ();
446 	gtk_label_set_mnemonic_widget (label, widget);
447 	gtk_grid_attach (GTK_GRID (grid), widget, 1, 1, 1, 1);
448 	page->priv->start_time = widget;  /* do not reference */
449 	gtk_widget_show (widget);
450 
451 	e_binding_bind_property (
452 		page->priv->scheduled_radio_button, "active",
453 		widget, "sensitive",
454 		G_BINDING_SYNC_CREATE);
455 
456 	widget = gtk_label_new_with_mnemonic (_("_To:"));
457 	gtk_widget_set_margin_left (widget, 12);
458 	gtk_misc_set_alignment (GTK_MISC (widget), 1.0, 0.5);
459 	gtk_grid_attach (GTK_GRID (grid), widget, 0, 2, 1, 1);
460 	gtk_size_group_add_widget (size_group, widget);
461 	gtk_widget_show (widget);
462 
463 	e_binding_bind_property (
464 		page->priv->scheduled_radio_button, "active",
465 		widget, "sensitive",
466 		G_BINDING_SYNC_CREATE);
467 
468 	label = GTK_LABEL (widget);
469 
470 	widget = e_date_edit_new ();
471 	gtk_label_set_mnemonic_widget (label, widget);
472 	gtk_grid_attach (GTK_GRID (grid), widget, 1, 2, 1, 1);
473 	page->priv->end_time = widget;  /* do not reference */
474 	gtk_widget_show (widget);
475 
476 	e_binding_bind_property (
477 		page->priv->scheduled_radio_button, "active",
478 		widget, "sensitive",
479 		G_BINDING_SYNC_CREATE);
480 
481 	widget = gtk_label_new_with_mnemonic (_("I_nternal:"));
482 	gtk_widget_set_margin_top (widget, 12);
483 	gtk_widget_set_margin_left (widget, 12);
484 	gtk_widget_set_valign (widget, GTK_ALIGN_START);
485 	gtk_misc_set_alignment (GTK_MISC (widget), 1.0, 0.5);
486 	gtk_grid_attach (GTK_GRID (grid), widget, 0, 3, 1, 1);
487 	gtk_size_group_add_widget (size_group, widget);
488 	gtk_widget_show (widget);
489 
490 	text = _("Message to be sent within the organization");
491 	gtk_widget_set_tooltip_text (widget, text);
492 
493 	label = GTK_LABEL (widget);
494 
495 	widget = gtk_scrolled_window_new (NULL, NULL);
496 	gtk_scrolled_window_set_policy (
497 		GTK_SCROLLED_WINDOW (widget),
498 		GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC);
499 	gtk_scrolled_window_set_shadow_type (
500 		GTK_SCROLLED_WINDOW (widget), GTK_SHADOW_IN);
501 	gtk_widget_set_margin_top (widget, 12);
502 	gtk_widget_set_hexpand (widget, TRUE);
503 	gtk_widget_set_vexpand (widget, TRUE);
504 	gtk_grid_attach (GTK_GRID (grid), widget, 1, 3, 1, 1);
505 	gtk_widget_show (widget);
506 
507 	container = widget;
508 
509 	widget = gtk_text_view_new ();
510 	gtk_label_set_mnemonic_widget (label, widget);
511 	gtk_text_view_set_wrap_mode (GTK_TEXT_VIEW (widget), GTK_WRAP_WORD);
512 	gtk_container_add (GTK_CONTAINER (container), widget);
513 	text_buffer = gtk_text_view_get_buffer (GTK_TEXT_VIEW (widget));
514 	page->priv->internal_reply = text_buffer;  /* do not reference */
515 	e_spell_text_view_attach (GTK_TEXT_VIEW (widget));
516 	gtk_widget_show (widget);
517 
518 	widget = gtk_label_new_with_mnemonic (_("E_xternal:"));
519 	gtk_widget_set_margin_top (widget, 12);
520 	gtk_widget_set_margin_left (widget, 12);
521 	gtk_misc_set_alignment (GTK_MISC (widget), 1.0, 0.5);
522 	gtk_grid_attach (GTK_GRID (grid), widget, 0, 4, 1, 1);
523 	gtk_size_group_add_widget (size_group, widget);
524 	gtk_widget_show (widget);
525 
526 	text = _("Message to be sent outside the organization");
527 	gtk_widget_set_tooltip_text (widget, text);
528 
529 	label = GTK_LABEL (widget);
530 
531 	/* The order of the combo box items needs to stay
532 	 * syncrhonized with the EEwsExternalAudience enum. */
533 	widget = gtk_combo_box_text_new ();
534 	gtk_combo_box_text_append_text (
535 		GTK_COMBO_BOX_TEXT (widget),
536 		_("Do not reply to senders outside the organization"));
537 	gtk_combo_box_text_append_text (
538 		GTK_COMBO_BOX_TEXT (widget),
539 		_("Reply only to known senders outside the organization"));
540 	gtk_combo_box_text_append_text (
541 		GTK_COMBO_BOX_TEXT (widget),
542 		_("Reply to any sender outside the organization"));
543 	gtk_widget_set_margin_top (widget, 12);
544 	gtk_grid_attach (GTK_GRID (grid), widget, 1, 4, 1, 1);
545 	page->priv->external_audience = widget;  /* do not reference */
546 	gtk_widget_show (widget);
547 
548 	widget = gtk_scrolled_window_new (NULL, NULL);
549 	gtk_scrolled_window_set_policy (
550 		GTK_SCROLLED_WINDOW (widget),
551 		GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC);
552 	gtk_scrolled_window_set_shadow_type (
553 		GTK_SCROLLED_WINDOW (widget), GTK_SHADOW_IN);
554 	gtk_widget_set_hexpand (widget, TRUE);
555 	gtk_widget_set_vexpand (widget, TRUE);
556 	gtk_grid_attach (GTK_GRID (grid), widget, 1, 5, 1, 1);
557 	gtk_widget_show (widget);
558 
559 	container = widget;
560 
561 	widget = gtk_text_view_new ();
562 	gtk_label_set_mnemonic_widget (label, widget);
563 	gtk_text_view_set_wrap_mode (GTK_TEXT_VIEW (widget), GTK_WRAP_WORD);
564 	gtk_container_add (GTK_CONTAINER (container), widget);
565 	text_buffer = gtk_text_view_get_buffer (GTK_TEXT_VIEW (widget));
566 	page->priv->external_reply = text_buffer;  /* do not reference */
567 	e_spell_text_view_attach (GTK_TEXT_VIEW (widget));
568 	gtk_widget_show (widget);
569 
570 	/* XXX Bit of a hack.  Since the enum value for "none" is zero,
571 	 *     sensitize the text view if the combo box has a non-zero
572 	 *     "active" value (in other words, anything but "none"). */
573 	e_binding_bind_property (
574 		page->priv->external_audience, "active",
575 		widget, "sensitive",
576 		G_BINDING_SYNC_CREATE);
577 
578 	g_object_unref (size_group);
579 
580 	e_mail_config_page_set_content (E_MAIL_CONFIG_PAGE (page), main_box);
581 
582 	e_mail_config_ews_ooo_page_refresh (page);
583 }
584 
585 /* Helper for mail_config_ews_ooo_page_submit() */
586 static void
mail_config_ews_ooo_page_submit_cb(GObject * source_object,GAsyncResult * result,gpointer user_data)587 mail_config_ews_ooo_page_submit_cb (GObject *source_object,
588                                     GAsyncResult *result,
589                                     gpointer user_data)
590 {
591 	GSimpleAsyncResult *simple;
592 	GError *error = NULL;
593 
594 	simple = G_SIMPLE_ASYNC_RESULT (user_data);
595 
596 	e_ews_oof_settings_submit_finish (
597 		E_EWS_OOF_SETTINGS (source_object), result, &error);
598 
599 	if (error != NULL)
600 		g_simple_async_result_take_error (simple, error);
601 
602 	g_simple_async_result_complete (simple);
603 
604 	g_object_unref (simple);
605 }
606 
607 static void
ews_oof_settings_changed(gboolean * pchanged)608 ews_oof_settings_changed (gboolean *pchanged)
609 {
610 	g_return_if_fail (pchanged != NULL);
611 
612 	*pchanged = TRUE;
613 }
614 
615 static void
mail_config_ews_ooo_page_submit(EMailConfigPage * page,GCancellable * cancellable,GAsyncReadyCallback callback,gpointer user_data)616 mail_config_ews_ooo_page_submit (EMailConfigPage *page,
617                                  GCancellable *cancellable,
618                                  GAsyncReadyCallback callback,
619                                  gpointer user_data)
620 {
621 	EMailConfigEwsOooPage *ooo_page;
622 	GSimpleAsyncResult *simple;
623 	GtkToggleButton *toggle_button;
624 	GtkTextBuffer *text_buffer;
625 	GtkTextIter start, end;
626 	GDateTime *date_time;
627 	gchar *text;
628 	time_t tm;
629 	gulong signal_id;
630 
631 	ooo_page = E_MAIL_CONFIG_EWS_OOO_PAGE (page);
632 
633 	g_mutex_lock (&ooo_page->priv->oof_settings_lock);
634 
635 	/* It may be that the Out of Office settings are still
636 	 * loading or have failed to load, in which case there
637 	 * are obviously no changes to submit. */
638 	if (!ooo_page->priv->oof_settings) {
639 		g_mutex_unlock (&ooo_page->priv->oof_settings_lock);
640 
641 		simple = g_simple_async_result_new (
642 			G_OBJECT (page), callback, user_data,
643 			mail_config_ews_ooo_page_submit);
644 		g_simple_async_result_complete (simple);
645 		g_object_unref (simple);
646 
647 		return;
648 	}
649 
650 	signal_id = g_signal_connect_swapped (
651 		ooo_page->priv->oof_settings, "notify",
652 		G_CALLBACK (ews_oof_settings_changed), &ooo_page->priv->changed);
653 
654 	toggle_button = GTK_TOGGLE_BUTTON (ooo_page->priv->enabled_radio_button);
655 	if (gtk_toggle_button_get_active (toggle_button))
656 		e_ews_oof_settings_set_state (
657 			ooo_page->priv->oof_settings,
658 			E_EWS_OOF_STATE_ENABLED);
659 
660 	toggle_button = GTK_TOGGLE_BUTTON (ooo_page->priv->disabled_radio_button);
661 	if (gtk_toggle_button_get_active (toggle_button))
662 		e_ews_oof_settings_set_state (
663 			ooo_page->priv->oof_settings,
664 			E_EWS_OOF_STATE_DISABLED);
665 
666 	toggle_button = GTK_TOGGLE_BUTTON (ooo_page->priv->scheduled_radio_button);
667 	if (gtk_toggle_button_get_active (toggle_button))
668 		e_ews_oof_settings_set_state (
669 			ooo_page->priv->oof_settings,
670 			E_EWS_OOF_STATE_SCHEDULED);
671 
672 	tm = e_date_edit_get_time (E_DATE_EDIT (ooo_page->priv->start_time));
673 	date_time = g_date_time_new_from_unix_utc ((gint64) tm);
674 	e_ews_oof_settings_set_start_time (ooo_page->priv->oof_settings, date_time);
675 	g_date_time_unref (date_time);
676 
677 	tm = e_date_edit_get_time (E_DATE_EDIT (ooo_page->priv->end_time));
678 	date_time = g_date_time_new_from_unix_utc ((gint64) tm);
679 	e_ews_oof_settings_set_end_time (ooo_page->priv->oof_settings, date_time);
680 	g_date_time_unref (date_time);
681 
682 	text_buffer = ooo_page->priv->internal_reply;
683 	gtk_text_buffer_get_bounds (text_buffer, &start, &end);
684 	text = gtk_text_buffer_get_text (text_buffer, &start, &end, FALSE);
685 	e_ews_oof_settings_set_internal_reply (ooo_page->priv->oof_settings, text);
686 	g_free (text);
687 
688 	e_ews_oof_settings_set_external_audience (ooo_page->priv->oof_settings,
689 		gtk_combo_box_get_active (GTK_COMBO_BOX (ooo_page->priv->external_audience)));
690 
691 	text_buffer = ooo_page->priv->external_reply;
692 	gtk_text_buffer_get_bounds (text_buffer, &start, &end);
693 	text = gtk_text_buffer_get_text (text_buffer, &start, &end, FALSE);
694 	e_ews_oof_settings_set_external_reply (ooo_page->priv->oof_settings, text);
695 	g_free (text);
696 
697 	simple = g_simple_async_result_new (
698 		G_OBJECT (page), callback, user_data,
699 		mail_config_ews_ooo_page_submit);
700 
701 	g_signal_handler_disconnect (ooo_page->priv->oof_settings, signal_id);
702 
703 	if (ooo_page->priv->changed) {
704 		g_simple_async_result_set_check_cancellable (simple, cancellable);
705 
706 		e_ews_oof_settings_submit (
707 			ooo_page->priv->oof_settings, cancellable,
708 			mail_config_ews_ooo_page_submit_cb,
709 			g_object_ref (simple));
710 	} else {
711 		g_simple_async_result_complete (simple);
712 	}
713 
714 	g_object_unref (simple);
715 
716 	g_mutex_unlock (&ooo_page->priv->oof_settings_lock);
717 }
718 
719 static gboolean
mail_config_ews_ooo_page_submit_finish(EMailConfigPage * page,GAsyncResult * result,GError ** error)720 mail_config_ews_ooo_page_submit_finish (EMailConfigPage *page,
721                                         GAsyncResult *result,
722                                         GError **error)
723 {
724 	GSimpleAsyncResult *simple;
725 
726 	g_return_val_if_fail (
727 		g_simple_async_result_is_valid (
728 		result, G_OBJECT (page),
729 		mail_config_ews_ooo_page_submit), FALSE);
730 
731 	simple = G_SIMPLE_ASYNC_RESULT (result);
732 
733 	/* Assume success unless a GError is set. */
734 	return !g_simple_async_result_propagate_error (simple, error);
735 }
736 
737 static ESourceAuthenticationResult
mail_config_ews_ooo_page_try_credentials_sync(EEwsConnection * connection,const ENamedParameters * credentials,gpointer user_data,GCancellable * cancellable,GError ** error)738 mail_config_ews_ooo_page_try_credentials_sync (EEwsConnection *connection,
739 					       const ENamedParameters *credentials,
740 					       gpointer user_data,
741 					       GCancellable *cancellable,
742 					       GError **error)
743 {
744 	AsyncContext *async_context = user_data;
745 	EMailConfigEwsOooPage *page;
746 	ESourceAuthenticationResult result;
747 	EEwsOofSettings *oof_settings;
748 	const gchar *mailbox;
749 	GError *local_error = NULL;
750 
751 	page = async_context->page;
752 
753 	mailbox = mail_config_ews_ooo_page_get_mailbox (page);
754 	e_ews_connection_set_mailbox (connection, mailbox);
755 
756 	oof_settings = e_ews_oof_settings_new_sync (connection, cancellable, &local_error);
757 
758 	if (oof_settings != NULL) {
759 		result = E_SOURCE_AUTHENTICATION_ACCEPTED;
760 		g_warn_if_fail (local_error == NULL);
761 
762 		/* The page takes ownership of the settings. */
763 		g_mutex_lock (&page->priv->oof_settings_lock);
764 		if (page->priv->oof_settings != NULL)
765 			g_object_unref (oof_settings);
766 		page->priv->oof_settings = oof_settings;
767 		page->priv->changed = FALSE;
768 		g_mutex_unlock (&page->priv->oof_settings_lock);
769 
770 	} else if (g_error_matches (local_error, SOUP_HTTP_ERROR, SOUP_STATUS_UNAUTHORIZED)) {
771 		result = E_SOURCE_AUTHENTICATION_REJECTED;
772 		g_error_free (local_error);
773 
774 	} else {
775 		result = E_SOURCE_AUTHENTICATION_ERROR;
776 		g_propagate_error (error, local_error);
777 	}
778 
779 	return result;
780 }
781 
782 static void
mail_config_ews_ooo_page_refresh_thread_cb(GObject * with_object,gpointer user_data,GCancellable * cancellable,GError ** perror)783 mail_config_ews_ooo_page_refresh_thread_cb (GObject *with_object,
784 					    gpointer user_data,
785 					    GCancellable *cancellable,
786 					    GError **perror)
787 {
788 	AsyncContext *async_context = user_data;
789 	CamelEwsSettings *ews_settings;
790 	EEwsConnection *connection;
791 
792 	if (g_cancellable_set_error_if_cancelled (cancellable, perror))
793 		return;
794 
795 	ews_settings = CAMEL_EWS_SETTINGS (async_context->settings);
796 	connection = e_ews_config_utils_open_connection_for (async_context->source, ews_settings, NULL,
797 		mail_config_ews_ooo_page_try_credentials_sync, async_context, cancellable, perror);
798 
799 	g_clear_object (&connection);
800 }
801 
802 static void
mail_config_ews_ooo_page_refresh_idle_cb(GObject * with_object,gpointer user_data,GCancellable * cancellable,GError ** perror)803 mail_config_ews_ooo_page_refresh_idle_cb (GObject *with_object,
804 					  gpointer user_data,
805 					  GCancellable *cancellable,
806 					  GError **perror)
807 {
808 	AsyncContext *async_context;
809 	EAlertSink *alert_sink;
810 	GError *error = NULL;
811 
812 	async_context = (AsyncContext *) user_data;
813 
814 	if (perror) {
815 		error = *perror;
816 		*perror = NULL;
817 	}
818 
819 	alert_sink = e_activity_get_alert_sink (async_context->activity);
820 
821 	if (e_activity_handle_cancellation (async_context->activity, error)) {
822 		g_error_free (error);
823 
824 	} else if (error != NULL) {
825 		e_alert_submit (
826 			alert_sink,
827 			"ews:query-ooo-error",
828 			error->message, NULL);
829 		g_error_free (error);
830 
831 	} else {
832 		EMailConfigEwsOooPage *page = async_context->page;
833 
834 		g_mutex_lock (&page->priv->oof_settings_lock);
835 
836 		if (page->priv->oof_settings != NULL)
837 			mail_config_ews_ooo_page_display_settings (
838 				page, page->priv->oof_settings);
839 
840 		g_mutex_unlock (&page->priv->oof_settings_lock);
841 	}
842 }
843 
844 static void
e_mail_config_ews_ooo_page_class_init(EMailConfigEwsOooPageClass * class)845 e_mail_config_ews_ooo_page_class_init (EMailConfigEwsOooPageClass *class)
846 {
847 	GObjectClass *object_class;
848 
849 	object_class = G_OBJECT_CLASS (class);
850 	object_class->set_property = mail_config_ews_ooo_page_set_property;
851 	object_class->get_property = mail_config_ews_ooo_page_get_property;
852 	object_class->dispose = mail_config_ews_ooo_page_dispose;
853 	object_class->finalize = mail_config_ews_ooo_page_finalize;
854 	object_class->constructed = mail_config_ews_ooo_page_constructed;
855 
856 	g_object_class_install_property (
857 		object_class,
858 		PROP_ACCOUNT_SOURCE,
859 		g_param_spec_object (
860 			"account-source",
861 			"Account Source",
862 			"Mail account source being edited",
863 			E_TYPE_SOURCE,
864 			G_PARAM_READWRITE |
865 			G_PARAM_CONSTRUCT_ONLY));
866 
867 	g_object_class_install_property (
868 		object_class,
869 		PROP_COLLECTION_SOURCE,
870 		g_param_spec_object (
871 			"collection-source",
872 			"Collection Source",
873 			"Collection source being edited",
874 			E_TYPE_SOURCE,
875 			G_PARAM_READWRITE |
876 			G_PARAM_CONSTRUCT_ONLY));
877 
878 	g_object_class_install_property (
879 		object_class,
880 		PROP_IDENTITY_SOURCE,
881 		g_param_spec_object (
882 			"identity-source",
883 			"Identity Source",
884 			"Mail identity source being edited",
885 			E_TYPE_SOURCE,
886 			G_PARAM_READWRITE |
887 			G_PARAM_CONSTRUCT_ONLY));
888 
889 	g_object_class_install_property (
890 		object_class,
891 		PROP_REGISTRY,
892 		g_param_spec_object (
893 			"registry",
894 			"Registry",
895 			"Data source registry",
896 			E_TYPE_SOURCE_REGISTRY,
897 			G_PARAM_READWRITE |
898 			G_PARAM_CONSTRUCT_ONLY));
899 }
900 
901 static void
e_mail_config_ews_ooo_page_interface_init(EMailConfigPageInterface * iface)902 e_mail_config_ews_ooo_page_interface_init (EMailConfigPageInterface *iface)
903 {
904 	iface->title = _("Out of Office");
905 	iface->sort_order = E_MAIL_CONFIG_EWS_OOO_PAGE_SORT_ORDER;
906 	iface->submit = mail_config_ews_ooo_page_submit;
907 	iface->submit_finish = mail_config_ews_ooo_page_submit_finish;
908 }
909 
910 static void
e_mail_config_ews_ooo_page_class_finalize(EMailConfigEwsOooPageClass * class)911 e_mail_config_ews_ooo_page_class_finalize (EMailConfigEwsOooPageClass *class)
912 {
913 }
914 
915 static void
e_mail_config_ews_ooo_page_init(EMailConfigEwsOooPage * page)916 e_mail_config_ews_ooo_page_init (EMailConfigEwsOooPage *page)
917 {
918 	page->priv = e_mail_config_ews_ooo_page_get_instance_private (page);
919 
920 	g_mutex_init (&page->priv->oof_settings_lock);
921 }
922 
923 void
e_mail_config_ews_ooo_page_type_register(GTypeModule * type_module)924 e_mail_config_ews_ooo_page_type_register (GTypeModule *type_module)
925 {
926 	/* XXX G_DEFINE_DYNAMIC_TYPE declares a static type registration
927 	 *     function, so we have to wrap it with a public function in
928 	 *     order to register types from a separate compilation unit. */
929 	e_mail_config_ews_ooo_page_register_type (type_module);
930 }
931 
932 EMailConfigPage *
e_mail_config_ews_ooo_page_new(ESourceRegistry * registry,ESource * account_source,ESource * identity_source,ESource * collection_source)933 e_mail_config_ews_ooo_page_new (ESourceRegistry *registry,
934                                 ESource *account_source,
935                                 ESource *identity_source,
936                                 ESource *collection_source)
937 {
938 	g_return_val_if_fail (E_IS_SOURCE_REGISTRY (registry), NULL);
939 	g_return_val_if_fail (E_IS_SOURCE (account_source), NULL);
940 	g_return_val_if_fail (E_IS_SOURCE (identity_source), NULL);
941 	g_return_val_if_fail (E_IS_SOURCE (collection_source), NULL);
942 
943 	return g_object_new (
944 		E_TYPE_MAIL_CONFIG_EWS_OOO_PAGE,
945 		"registry", registry,
946 		"account-source", account_source,
947 		"identity-source", identity_source,
948 		"collection-source", collection_source,
949 		NULL);
950 }
951 
952 void
e_mail_config_ews_ooo_page_refresh(EMailConfigEwsOooPage * page)953 e_mail_config_ews_ooo_page_refresh (EMailConfigEwsOooPage *page)
954 {
955 	ESource *source;
956 	EActivity *activity;
957 	GCancellable *cancellable;
958 	CamelSettings *settings;
959 	AsyncContext *async_context;
960 
961 	g_return_if_fail (E_IS_MAIL_CONFIG_EWS_OOO_PAGE (page));
962 
963 	source = e_mail_config_ews_ooo_page_get_collection_source (page);
964 
965 	if (page->priv->refresh_cancellable) {
966 		g_cancellable_cancel (page->priv->refresh_cancellable);
967 		g_clear_object (&page->priv->refresh_cancellable);
968 	}
969 
970 	activity = e_mail_config_activity_page_new_activity (
971 		E_MAIL_CONFIG_ACTIVITY_PAGE (page));
972 	cancellable = e_activity_get_cancellable (activity);
973 	page->priv->refresh_cancellable = g_object_ref (cancellable);
974 
975 	e_activity_set_text (
976 		activity, _("Retrieving “Out of Office” settings"));
977 
978 	settings = mail_config_ews_ooo_page_get_settings (page);
979 
980 	async_context = g_slice_new0 (AsyncContext);
981 	async_context->page = g_object_ref (page);
982 	async_context->activity = activity;  /* takes ownership */
983 	async_context->source = g_object_ref (source);
984 	async_context->settings = G_OBJECT (g_object_ref (settings));
985 
986 	/* Property changes can cause update of the UI, but this runs in a thread,
987 	   thus freeze the notify till be back in UI thread */
988 	g_object_freeze_notify (async_context->settings);
989 
990 	e_ews_config_utils_run_in_thread (G_OBJECT (page),
991 		mail_config_ews_ooo_page_refresh_thread_cb,
992 		mail_config_ews_ooo_page_refresh_idle_cb,
993 		async_context, async_context_free, cancellable);
994 }
995 
996 ESourceRegistry *
e_mail_config_ews_ooo_page_get_registry(EMailConfigEwsOooPage * page)997 e_mail_config_ews_ooo_page_get_registry (EMailConfigEwsOooPage *page)
998 {
999 	g_return_val_if_fail (E_IS_MAIL_CONFIG_EWS_OOO_PAGE (page), NULL);
1000 
1001 	return page->priv->registry;
1002 }
1003 
1004 ESource *
e_mail_config_ews_ooo_page_get_account_source(EMailConfigEwsOooPage * page)1005 e_mail_config_ews_ooo_page_get_account_source (EMailConfigEwsOooPage *page)
1006 {
1007 	g_return_val_if_fail (E_IS_MAIL_CONFIG_EWS_OOO_PAGE (page), NULL);
1008 
1009 	return page->priv->account_source;
1010 }
1011 
1012 ESource *
e_mail_config_ews_ooo_page_get_identity_source(EMailConfigEwsOooPage * page)1013 e_mail_config_ews_ooo_page_get_identity_source (EMailConfigEwsOooPage *page)
1014 {
1015 	g_return_val_if_fail (E_IS_MAIL_CONFIG_EWS_OOO_PAGE (page), NULL);
1016 
1017 	return page->priv->identity_source;
1018 }
1019 
1020 ESource *
e_mail_config_ews_ooo_page_get_collection_source(EMailConfigEwsOooPage * page)1021 e_mail_config_ews_ooo_page_get_collection_source (EMailConfigEwsOooPage *page)
1022 {
1023 	g_return_val_if_fail (E_IS_MAIL_CONFIG_EWS_OOO_PAGE (page), NULL);
1024 
1025 	return page->priv->collection_source;
1026 }
1027 
1028