1 /*
2  * e-cal-config-google.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 
24 #include <e-util/e-util.h>
25 
26 #include "e-google-chooser-button.h"
27 #include "module-cal-config-google.h"
28 
29 #define GOOGLE_CALENDAR_URI	"https://calendar.google.com/calendar/syncselect"
30 
31 typedef ESourceConfigBackend ECalConfigGoogle;
32 typedef ESourceConfigBackendClass ECalConfigGoogleClass;
33 
34 typedef struct _Context Context;
35 
36 struct _Context {
37 	GtkWidget *google_button;
38 	GtkWidget *user_entry;
39 };
40 
41 /* Forward Declarations */
42 GType e_cal_config_google_get_type (void);
43 
G_DEFINE_DYNAMIC_TYPE(ECalConfigGoogle,e_cal_config_google,E_TYPE_SOURCE_CONFIG_BACKEND)44 G_DEFINE_DYNAMIC_TYPE (
45 	ECalConfigGoogle,
46 	e_cal_config_google,
47 	E_TYPE_SOURCE_CONFIG_BACKEND)
48 
49 static void
50 cal_config_google_context_free (Context *context)
51 {
52 	g_object_unref (context->google_button);
53 	g_object_unref (context->user_entry);
54 
55 	g_slice_free (Context, context);
56 }
57 
58 static gboolean
cal_config_google_allow_creation(ESourceConfigBackend * backend)59 cal_config_google_allow_creation (ESourceConfigBackend *backend)
60 {
61 	ESourceConfig *config;
62 	ECalClientSourceType source_type;
63 
64 	config = e_source_config_backend_get_config (backend);
65 
66 	source_type = e_cal_source_config_get_source_type (
67 		E_CAL_SOURCE_CONFIG (config));
68 
69 	/* XXX Google's CalDAV interface doesn't support tasks. */
70 	return (source_type == E_CAL_CLIENT_SOURCE_TYPE_EVENTS);
71 }
72 
73 static void
cal_config_google_insert_widgets(ESourceConfigBackend * backend,ESource * scratch_source)74 cal_config_google_insert_widgets (ESourceConfigBackend *backend,
75                                   ESource *scratch_source)
76 {
77 	ESourceConfig *config;
78 	GtkWidget *widget;
79 	Context *context;
80 	const gchar *uid;
81 	gchar *markup;
82 
83 	context = g_slice_new0 (Context);
84 	uid = e_source_get_uid (scratch_source);
85 	config = e_source_config_backend_get_config (backend);
86 
87 	g_object_set_data_full (
88 		G_OBJECT (backend), uid, context,
89 		(GDestroyNotify) cal_config_google_context_free);
90 
91 	context->user_entry = g_object_ref (e_source_config_add_user_entry (config, scratch_source));
92 
93 	widget = e_google_chooser_button_new (scratch_source, config);
94 	e_source_config_insert_widget (config, scratch_source, _("Calendar:"), widget);
95 	context->google_button = g_object_ref (widget);
96 	gtk_widget_show (widget);
97 
98 	markup = g_markup_printf_escaped ("<a href=\"%s\">%s</a>", GOOGLE_CALENDAR_URI, _("Enable Calendars to synchronize"));
99 
100 	widget = gtk_label_new (markup);
101 	gtk_label_set_use_markup (GTK_LABEL (widget), TRUE);
102 	gtk_misc_set_alignment (GTK_MISC (widget), 0.0, 0.5);
103 	e_source_config_insert_widget (config, scratch_source, NULL, widget);
104 	gtk_widget_show (widget);
105 
106 	g_free (markup);
107 
108 	e_source_config_add_refresh_interval (config, scratch_source);
109 }
110 
111 static void
cal_config_google_commit_changes(ESourceConfigBackend * backend,ESource * scratch_source)112 cal_config_google_commit_changes (ESourceConfigBackend *backend,
113                                   ESource *scratch_source)
114 {
115 	ESourceBackend *calendar_extension;
116 	ESourceWebdav *webdav_extension;
117 	ESourceAuthentication *authentication_extension;
118 	gboolean can_google_auth;
119 	SoupURI *soup_uri;
120 
121 	/* We need to hard-code a few settings. */
122 
123 	calendar_extension = e_source_get_extension (
124 		scratch_source, E_SOURCE_EXTENSION_CALENDAR);
125 
126 	webdav_extension = e_source_get_extension (
127 		scratch_source, E_SOURCE_EXTENSION_WEBDAV_BACKEND);
128 
129 	authentication_extension = e_source_get_extension (
130 		scratch_source, E_SOURCE_EXTENSION_AUTHENTICATION);
131 
132 	can_google_auth = e_module_cal_config_google_is_supported (backend, NULL) &&
133 			  g_strcmp0 (e_source_authentication_get_method (authentication_extension), "OAuth2") != 0;
134 
135 	/* The backend name is actually "caldav" even though the
136 	 * ESource is a child of the built-in "Google" source. */
137 	e_source_backend_set_backend_name (calendar_extension, "caldav");
138 
139 	soup_uri = e_source_webdav_dup_soup_uri (webdav_extension);
140 
141 	if (can_google_auth || g_strcmp0 (e_source_authentication_get_method (authentication_extension), "Google") == 0) {
142 		/* Prefer 'Google', aka internal OAuth2, authentication method, if available */
143 		e_source_authentication_set_method (authentication_extension, "Google");
144 
145 		/* See https://developers.google.com/google-apps/calendar/caldav/v2/guide */
146 		soup_uri_set_host (soup_uri, "apidata.googleusercontent.com");
147 	} else {
148 		soup_uri_set_host (soup_uri, "www.google.com");
149 	}
150 
151 	if (!soup_uri->path || !*soup_uri->path || g_strcmp0 (soup_uri->path, "/") == 0) {
152 		ESourceAuthentication *authentication_extension
153 			= e_source_get_extension (scratch_source, E_SOURCE_EXTENSION_AUTHENTICATION);
154 
155 		e_google_chooser_button_construct_default_uri (
156 			soup_uri,
157 			e_source_authentication_get_user (authentication_extension));
158 	}
159 
160 	/* Google's CalDAV interface requires a secure connection. */
161 	soup_uri_set_scheme (soup_uri, SOUP_URI_SCHEME_HTTPS);
162 
163 	e_source_webdav_set_soup_uri (webdav_extension, soup_uri);
164 
165 	soup_uri_free (soup_uri);
166 }
167 
168 static gboolean
cal_config_google_check_complete(ESourceConfigBackend * backend,ESource * scratch_source)169 cal_config_google_check_complete (ESourceConfigBackend *backend,
170                                   ESource *scratch_source)
171 {
172 	ESourceAuthentication *extension;
173 	Context *context;
174 	gboolean correct;
175 	const gchar *extension_name;
176 	const gchar *user;
177 
178 	context = g_object_get_data (G_OBJECT (backend), e_source_get_uid (scratch_source));
179 	g_return_val_if_fail (context != NULL, FALSE);
180 
181 	extension_name = E_SOURCE_EXTENSION_AUTHENTICATION;
182 	extension = e_source_get_extension (scratch_source, extension_name);
183 	user = e_source_authentication_get_user (extension);
184 
185 	correct = (user != NULL);
186 
187 	e_util_set_entry_issue_hint (context->user_entry, correct ? NULL : _("User name cannot be empty"));
188 
189 	return correct;
190 }
191 
192 static void
e_cal_config_google_class_init(ESourceConfigBackendClass * class)193 e_cal_config_google_class_init (ESourceConfigBackendClass *class)
194 {
195 	EExtensionClass *extension_class;
196 
197 	extension_class = E_EXTENSION_CLASS (class);
198 	extension_class->extensible_type = E_TYPE_CAL_SOURCE_CONFIG;
199 
200 	class->parent_uid = "google-stub";
201 	class->backend_name = "google";
202 	class->allow_creation = cal_config_google_allow_creation;
203 	class->insert_widgets = cal_config_google_insert_widgets;
204 	class->check_complete = cal_config_google_check_complete;
205 	class->commit_changes = cal_config_google_commit_changes;
206 }
207 
208 static void
e_cal_config_google_class_finalize(ESourceConfigBackendClass * class)209 e_cal_config_google_class_finalize (ESourceConfigBackendClass *class)
210 {
211 }
212 
213 static void
e_cal_config_google_init(ESourceConfigBackend * backend)214 e_cal_config_google_init (ESourceConfigBackend *backend)
215 {
216 }
217 
218 void
e_cal_config_google_type_register(GTypeModule * type_module)219 e_cal_config_google_type_register (GTypeModule *type_module)
220 {
221 	e_cal_config_google_register_type (type_module);
222 }
223