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 <glib/gi18n-lib.h>
10 #include <gtk/gtk.h>
11
12 #include <libemail-engine/libemail-engine.h>
13
14 #include "camel/camel-ews-store.h"
15 #include "camel/camel-ews-store-summary.h"
16 #include "camel/camel-ews-utils.h"
17
18 #include "common/e-ews-calendar-utils.h"
19
20 #include "e-ews-config-utils.h"
21 #include "e-ews-search-user.h"
22 #include "e-ews-subscribe-foreign-folder.h"
23
24 #define STR_ACCOUNTS_COMBO "e-ews-accounts-combo"
25 #define STR_USER_NAME_SELECTOR_ENTRY "e-ews-name-selector-entry"
26 #define STR_FOLDER_NAME_COMBO "e-ews-folder-name-combo"
27 #define STR_SUBFOLDERS_CHECK "e-ews-subfolders-check"
28 #define STR_EWS_CAMEL_SESSION "e-ews-camel-session"
29 #define STR_EWS_DIRECT_EMAIL "e-ews-direct-email"
30
31 enum {
32 COLUMN_UID = 0,
33 COLUMN_DISPLAY_NAME,
34 COLUMN_STORE
35 };
36
37 static void
announce_new_folder(CamelEwsStore * ews_store,const gchar * fid)38 announce_new_folder (CamelEwsStore *ews_store,
39 const gchar *fid)
40 {
41 CamelFolderInfo *fi;
42
43 g_return_if_fail (CAMEL_IS_EWS_STORE (ews_store));
44 g_return_if_fail (fid != NULL);
45 g_return_if_fail (camel_ews_store_summary_has_folder (ews_store->summary, fid));
46
47 fi = camel_ews_utils_build_folder_info (ews_store, fid);
48 camel_store_folder_created (CAMEL_STORE (ews_store), fi);
49 camel_subscribable_folder_subscribed (CAMEL_SUBSCRIBABLE (ews_store), fi);
50 camel_folder_info_free (fi);
51 }
52
53 static gboolean
add_foreign_folder_to_camel(CamelEwsStore * ews_store,const gchar * foreign_email,EEwsFolder * folder,gboolean include_subfolders,const gchar * display_username,const gchar * display_foldername,GError ** perror)54 add_foreign_folder_to_camel (CamelEwsStore *ews_store,
55 const gchar *foreign_email,
56 EEwsFolder *folder,
57 gboolean include_subfolders,
58 const gchar *display_username,
59 const gchar *display_foldername,
60 GError **perror)
61 {
62 gchar *foreign_mailbox_id;
63 gchar *mailbox, *fullname;
64 const EwsFolderId *fid, *parent_fid;
65
66 g_return_val_if_fail (ews_store != NULL, FALSE);
67 g_return_val_if_fail (ews_store->summary != NULL, FALSE);
68 g_return_val_if_fail (foreign_email != NULL, FALSE);
69 g_return_val_if_fail (folder != NULL, FALSE);
70 g_return_val_if_fail (display_username != NULL, FALSE);
71 g_return_val_if_fail (display_foldername != NULL, FALSE);
72
73 fid = e_ews_folder_get_id (folder);
74 parent_fid = e_ews_folder_get_parent_id (folder);
75
76 g_return_val_if_fail (fid != NULL, FALSE);
77 g_return_val_if_fail (parent_fid != NULL, FALSE);
78 g_return_val_if_fail (g_strcmp0 (fid->id, parent_fid->id) != 0, FALSE);
79
80 if (camel_ews_store_summary_has_folder (ews_store->summary, fid->id)) {
81 gchar *full_name = camel_ews_store_summary_get_folder_full_name (ews_store->summary, fid->id, NULL);
82
83 g_propagate_error (
84 perror,
85 g_error_new (EWS_CONNECTION_ERROR, EWS_CONNECTION_ERROR_FOLDEREXISTS,
86 _("Cannot add folder, folder already exists as “%s”"), full_name));
87
88 g_free (full_name);
89
90 return FALSE;
91 }
92
93 /* Translators: The '%s' is replaced with user name, to whom the foreign mailbox belongs.
94 * Example result: "Mailbox — John Smith"
95 */
96 mailbox = g_strdup_printf (C_("ForeignFolder", "Mailbox — %s"), display_username);
97
98 foreign_mailbox_id = g_strdup_printf ("ForeignMailbox::%s", foreign_email);
99 if (!camel_ews_store_summary_has_folder (ews_store->summary, foreign_mailbox_id)) {
100 camel_ews_store_summary_new_folder (
101 ews_store->summary,
102 foreign_mailbox_id, EWS_FOREIGN_FOLDER_ROOT_ID, NULL,
103 mailbox, E_EWS_FOLDER_TYPE_MAILBOX,
104 CAMEL_FOLDER_SYSTEM | CAMEL_FOLDER_NOSELECT,
105 0, FALSE, FALSE);
106 }
107
108 if (camel_ews_store_summary_has_folder (ews_store->summary, parent_fid->id)) {
109 camel_ews_store_summary_new_folder (
110 ews_store->summary,
111 fid->id, parent_fid->id, fid->change_key,
112 display_foldername, E_EWS_FOLDER_TYPE_MAILBOX,
113 CAMEL_FOLDER_SUBSCRIBED, e_ews_folder_get_total_count (folder), TRUE, FALSE);
114 } else {
115 const gchar *displayname;
116 gchar *escaped_name;
117
118 escaped_name = e_ews_folder_utils_escape_name (display_foldername);
119 fullname = g_strdup_printf ("%s/%s/%s", EWS_FOREIGN_FOLDER_ROOT_DISPLAY_NAME, mailbox, escaped_name);
120 g_free (escaped_name);
121
122 /* make sure the path is unique */
123 camel_ews_store_ensure_unique_path (ews_store, &fullname);
124
125 displayname = strrchr (fullname, '/');
126 displayname++;
127
128 camel_ews_store_summary_new_folder (
129 ews_store->summary,
130 fid->id, foreign_mailbox_id, fid->change_key,
131 displayname, E_EWS_FOLDER_TYPE_MAILBOX,
132 CAMEL_FOLDER_SUBSCRIBED, e_ews_folder_get_total_count (folder), TRUE, FALSE);
133
134 g_free (fullname);
135 }
136
137 camel_ews_store_ensure_virtual_folders (ews_store);
138 camel_ews_store_summary_set_foreign_subfolders (ews_store->summary, fid->id, include_subfolders);
139 camel_ews_store_summary_save (ews_store->summary, perror);
140
141 announce_new_folder (ews_store, EWS_FOREIGN_FOLDER_ROOT_ID);
142 announce_new_folder (ews_store, foreign_mailbox_id);
143 announce_new_folder (ews_store, fid->id);
144
145 g_free (foreign_mailbox_id);
146 g_free (mailbox);
147
148 if (include_subfolders)
149 camel_ews_store_update_foreign_subfolders (ews_store, fid->id);
150
151 return TRUE;
152 }
153
154 static void
enable_ok_button_by_data(GObject * dialog)155 enable_ok_button_by_data (GObject *dialog)
156 {
157 GtkEntry *entry;
158 GtkComboBoxText *combo;
159 const gchar *entry_text;
160 gchar *combo_text;
161
162 g_return_if_fail (dialog != NULL);
163
164 entry = g_object_get_data (dialog, STR_USER_NAME_SELECTOR_ENTRY);
165 g_return_if_fail (entry != NULL);
166
167 combo = g_object_get_data (dialog, STR_FOLDER_NAME_COMBO);
168 g_return_if_fail (combo != NULL);
169
170 entry_text = gtk_entry_get_text (entry);
171 combo_text = gtk_combo_box_text_get_active_text (combo);
172
173 gtk_dialog_set_response_sensitive (
174 GTK_DIALOG (dialog), GTK_RESPONSE_OK,
175 entry_text && *entry_text && *entry_text != ' ' && *entry_text != ',' &&
176 combo_text && *combo_text);
177
178 g_free (combo_text);
179 }
180
181 static void
name_entry_changed_cb(GObject * dialog)182 name_entry_changed_cb (GObject *dialog)
183 {
184 GtkEntry *entry;
185
186 g_return_if_fail (dialog != NULL);
187
188 entry = g_object_get_data (dialog, STR_USER_NAME_SELECTOR_ENTRY);
189 g_return_if_fail (entry != NULL);
190
191 g_object_set_data (G_OBJECT (entry), STR_EWS_DIRECT_EMAIL, NULL);
192
193 enable_ok_button_by_data (dialog);
194 }
195
196 static void
folder_name_combo_changed_cb(GObject * dialog,GtkComboBox * combo)197 folder_name_combo_changed_cb (GObject *dialog,
198 GtkComboBox *combo)
199 {
200 enable_ok_button_by_data (dialog);
201 }
202
203 struct EEwsCheckForeignFolderData
204 {
205 GtkWidget *dialog;
206 gboolean include_subfolders;
207 gchar *email;
208 gchar *direct_email;
209 gchar *user_displayname;
210 gchar *orig_foldername;
211 gchar *use_foldername;
212 EEwsFolder *folder;
213 };
214
215 static void
e_ews_check_foreign_folder_data_free(gpointer ptr)216 e_ews_check_foreign_folder_data_free (gpointer ptr)
217 {
218 struct EEwsCheckForeignFolderData *cffd = ptr;
219
220 if (!cffd)
221 return;
222
223 g_free (cffd->email);
224 g_free (cffd->direct_email);
225 g_free (cffd->user_displayname);
226 g_free (cffd->orig_foldername);
227 g_free (cffd->use_foldername);
228
229 /* folder tells whether successfully finished,
230 * then the dialog can be destroyed */
231 if (cffd->folder && cffd->dialog)
232 gtk_widget_destroy (cffd->dialog);
233
234 if (cffd->folder)
235 g_object_unref (cffd->folder);
236
237 g_slice_free (struct EEwsCheckForeignFolderData, cffd);
238 }
239
240 static void
check_foreign_folder_thread(GObject * with_object,gpointer user_data,GCancellable * cancellable,GError ** perror)241 check_foreign_folder_thread (GObject *with_object,
242 gpointer user_data,
243 GCancellable *cancellable,
244 GError **perror)
245 {
246 struct EEwsCheckForeignFolderData *cffd = user_data;
247 GError *local_error = NULL;
248 EEwsConnection *conn;
249 EwsFolderId fid;
250 EEwsFolder *folder = NULL;
251
252 g_return_if_fail (with_object != NULL);
253 g_return_if_fail (CAMEL_IS_EWS_STORE (with_object));
254 g_return_if_fail (user_data != NULL);
255 g_return_if_fail (cffd->email != NULL);
256
257 if (g_cancellable_set_error_if_cancelled (cancellable, perror))
258 return;
259
260 conn = camel_ews_store_ref_connection (CAMEL_EWS_STORE (with_object));
261 if (!conn) {
262 g_set_error_literal (
263 perror, EWS_CONNECTION_ERROR, EWS_CONNECTION_ERROR_NORESPONSE,
264 _("Cannot test foreign folder availability when the account is offline"));
265 return;
266 }
267
268 if (cffd->direct_email && *cffd->direct_email) {
269 g_return_if_fail (cffd->user_displayname == NULL);
270
271 cffd->user_displayname = cffd->email;
272 cffd->email = g_strdup (cffd->direct_email);
273 } else {
274 gchar *display_name = NULL, *email_address = NULL;
275
276 if (!e_ews_subscribe_foreign_folder_resolve_name_sync (conn, cffd->email, &display_name, &email_address, cancellable, perror)) {
277 g_object_unref (conn);
278 return;
279 }
280 }
281
282 if (g_cancellable_set_error_if_cancelled (cancellable, perror)) {
283 g_object_unref (conn);
284 return;
285 }
286
287 if (g_strcmp0 (cffd->use_foldername, "freebusy-calendar") == 0) {
288 EEWSFreeBusyData fbdata;
289 GSList *free_busy = NULL;
290 gchar *tmp;
291 gboolean success;
292
293 fbdata.period_start = time (NULL);
294 fbdata.period_end = fbdata.period_start + (60 * 60);
295 fbdata.user_mails = g_slist_prepend (NULL, cffd->email);
296
297 success = e_ews_connection_get_free_busy_sync (conn, G_PRIORITY_DEFAULT,
298 e_ews_cal_utils_prepare_free_busy_request, &fbdata,
299 &free_busy, cancellable, perror);
300
301 g_slist_free_full (free_busy, g_object_unref);
302 g_slist_free (fbdata.user_mails);
303
304 if (!success) {
305 g_object_unref (conn);
306 return;
307 }
308
309 tmp = g_strconcat (cffd->use_foldername, "::", cffd->email, NULL);
310
311 folder = g_object_new (E_TYPE_EWS_FOLDER, NULL);
312 e_ews_folder_set_id (folder, e_ews_folder_id_new (tmp, NULL, FALSE));
313 /* Translators: This is used as a calendar name; it constructs "User Name - Availability" string shown in UI */
314 e_ews_folder_set_name (folder, _("Availability"));
315 e_ews_folder_set_folder_type (folder, E_EWS_FOLDER_TYPE_CALENDAR);
316 e_ews_folder_set_foreign_mail (folder, cffd->email);
317
318 g_free (tmp);
319 } else {
320 fid.id = (gchar *) (cffd->use_foldername ? cffd->use_foldername : cffd->orig_foldername);
321 fid.change_key = NULL;
322 fid.is_distinguished_id = cffd->use_foldername != NULL || (cffd->orig_foldername && strlen (cffd->orig_foldername) < 40);
323
324 if (!e_ews_connection_get_folder_info_sync (conn, G_PRIORITY_DEFAULT,
325 cffd->email, &fid, &folder, cancellable, &local_error)) {
326 if (!local_error ||
327 g_error_matches (local_error, EWS_CONNECTION_ERROR, EWS_CONNECTION_ERROR_ITEMNOTFOUND) ||
328 g_error_matches (local_error, EWS_CONNECTION_ERROR, EWS_CONNECTION_ERROR_FOLDERNOTFOUND)) {
329 g_clear_error (&local_error);
330 local_error = g_error_new (
331 EWS_CONNECTION_ERROR, EWS_CONNECTION_ERROR_FOLDERNOTFOUND,
332 _("Folder “%s” not found. Either it does not exist or you do not have permission to access it."),
333 cffd->orig_foldername);
334 }
335
336 g_propagate_error (perror, local_error);
337 g_object_unref (conn);
338 return;
339 }
340 }
341
342 if (g_cancellable_set_error_if_cancelled (cancellable, perror)) {
343 g_object_unref (folder);
344 g_object_unref (conn);
345 return;
346 }
347
348 if (e_ews_folder_get_folder_type (folder) == E_EWS_FOLDER_TYPE_UNKNOWN) {
349 g_propagate_error (
350 perror, g_error_new_literal (EWS_CONNECTION_ERROR,
351 EWS_CONNECTION_ERROR_FOLDERNOTFOUND, _("Cannot add folder, cannot determine folder’s type")));
352 g_object_unref (folder);
353 g_object_unref (conn);
354 return;
355 }
356
357 e_ews_folder_set_foreign (folder, TRUE);
358
359 cffd->folder = folder;
360 g_object_unref (conn);
361 }
362
363 static void
check_foreign_folder_idle(GObject * with_object,gpointer user_data,GCancellable * cancellable,GError ** perror)364 check_foreign_folder_idle (GObject *with_object,
365 gpointer user_data,
366 GCancellable *cancellable,
367 GError **perror)
368 {
369 struct EEwsCheckForeignFolderData *cffd = user_data;
370
371 g_return_if_fail (with_object != NULL);
372 g_return_if_fail (CAMEL_IS_EWS_STORE (with_object));
373 g_return_if_fail (user_data != NULL);
374 g_return_if_fail (cffd->email != NULL);
375
376 if (!cffd->folder)
377 return;
378
379 if (!e_ews_subscrive_foreign_folder_subscribe_sync (CAMEL_EWS_STORE (with_object),
380 cffd->folder, cffd->user_displayname, cffd->email, cffd->orig_foldername,
381 cffd->include_subfolders, cancellable, perror)) {
382 /* to not destroy the dialog on error */
383 g_object_unref (cffd->folder);
384 cffd->folder = NULL;
385 }
386 }
387
388 static gpointer
ref_selected_store(GObject * dialog)389 ref_selected_store (GObject *dialog)
390 {
391 GtkComboBox *combo_box;
392 CamelStore *store = NULL;
393 GtkTreeIter iter;
394
395 combo_box = g_object_get_data (dialog, STR_ACCOUNTS_COMBO);
396 g_return_val_if_fail (combo_box != NULL, NULL);
397
398 if (gtk_combo_box_get_active_iter (combo_box, &iter)) {
399 gtk_tree_model_get (gtk_combo_box_get_model (combo_box), &iter,
400 COLUMN_STORE, &store, -1);
401 }
402
403 return store;
404 }
405
406 static void
subscribe_foreign_response_cb(GObject * dialog,gint response_id)407 subscribe_foreign_response_cb (GObject *dialog,
408 gint response_id)
409 {
410 struct EEwsCheckForeignFolderData *cffd;
411 ENameSelectorEntry *entry;
412 GtkComboBoxText *combo_text;
413 GtkToggleButton *subfolders_check;
414 EDestinationStore *dest_store;
415 CamelStore *cstore;
416 gchar *description;
417 const gchar *username;
418 gchar *orig_foldername, *use_foldername = NULL, *show_foldername = NULL;
419
420 if (response_id != GTK_RESPONSE_OK) {
421 gtk_widget_destroy (GTK_WIDGET (dialog));
422 return;
423 }
424
425 g_return_if_fail (dialog != NULL);
426
427 entry = g_object_get_data (dialog, STR_USER_NAME_SELECTOR_ENTRY);
428 combo_text = g_object_get_data (dialog, STR_FOLDER_NAME_COMBO);
429 subfolders_check = g_object_get_data (dialog, STR_SUBFOLDERS_CHECK);
430
431 g_return_if_fail (entry != NULL);
432
433 cstore = ref_selected_store (dialog);
434 g_return_if_fail (cstore != NULL);
435
436 username = NULL;
437 dest_store = e_name_selector_entry_peek_destination_store (entry);
438 if (dest_store && e_destination_store_get_destination_count (dest_store) > 0) {
439 EDestination *dest;
440 GList *dests = e_destination_store_list_destinations (dest_store);
441
442 g_return_if_fail (dests != NULL);
443
444 /* pick the first, there is no option to limit to only one destination */
445 dest = dests->data;
446 if (dest) {
447 username = e_destination_get_email (dest);
448 if (!username || !*username)
449 username = e_destination_get_name (dest);
450 }
451
452 g_list_free (dests);
453 }
454
455 if (!username || !*username)
456 username = gtk_entry_get_text (GTK_ENTRY (entry));
457
458 orig_foldername = gtk_combo_box_text_get_active_text (combo_text);
459 if (!orig_foldername)
460 orig_foldername = g_strdup ("");
461
462 /* convert well-known names to their non-localized form */
463 if (g_strcmp0 (orig_foldername, _("Inbox")) == 0) {
464 use_foldername = g_strdup ("inbox");
465 } else if (g_strcmp0 (orig_foldername, _("Contacts")) == 0) {
466 use_foldername = g_strdup ("contacts");
467 } else if (g_strcmp0 (orig_foldername, _("Calendar")) == 0) {
468 use_foldername = g_strdup ("calendar");
469 } else if (g_strcmp0 (orig_foldername, _("Free/Busy as Calendar")) == 0) {
470 use_foldername = g_strdup ("freebusy-calendar");
471 } else if (g_strcmp0 (orig_foldername, _("Memos")) == 0) {
472 use_foldername = g_strdup ("notes");
473 } else if (g_strcmp0 (orig_foldername, _("Tasks")) == 0) {
474 use_foldername = g_strdup ("tasks");
475 } else if (strlen (orig_foldername) > 13) {
476 /* if it's a folder ID, then show only first 10 letters of it */
477 show_foldername = g_strdup_printf ("%.10s…", orig_foldername);
478 }
479
480 cffd = g_slice_new0 (struct EEwsCheckForeignFolderData);
481 cffd->dialog = GTK_WIDGET (dialog);
482 cffd->email = g_strdup (username ? username : "");
483 cffd->direct_email = g_strdup (g_object_get_data (G_OBJECT (entry), STR_EWS_DIRECT_EMAIL));
484 cffd->orig_foldername = orig_foldername;
485 cffd->use_foldername = use_foldername;
486 cffd->include_subfolders = gtk_toggle_button_get_active (subfolders_check);
487 cffd->folder = NULL;
488
489 description = g_strdup_printf (
490 _("Testing availability of folder “%s” of user “%s”, please wait…"),
491 show_foldername ? show_foldername : cffd->orig_foldername, cffd->email);
492
493 e_ews_config_utils_run_in_thread_with_feedback (
494 GTK_WINDOW (dialog),
495 G_OBJECT (cstore),
496 description,
497 check_foreign_folder_thread,
498 check_foreign_folder_idle,
499 cffd,
500 e_ews_check_foreign_folder_data_free);
501
502 g_free (description);
503 g_free (show_foldername);
504 g_object_unref (cstore);
505 }
506
507 static void
pick_gal_user_clicked_cb(GtkButton * button,GObject * dialog)508 pick_gal_user_clicked_cb (GtkButton *button,
509 GObject *dialog)
510 {
511 GtkEntry *entry;
512 CamelEwsStore *ews_store;
513 EEwsConnection *conn;
514 gchar *text, *display_name = NULL, *email = NULL;
515
516 g_return_if_fail (dialog != NULL);
517
518 entry = g_object_get_data (dialog, STR_USER_NAME_SELECTOR_ENTRY);
519
520 g_return_if_fail (entry != NULL);
521
522 ews_store = ref_selected_store (dialog);
523 g_return_if_fail (ews_store != NULL);
524
525 text = g_strstrip (g_strdup (gtk_entry_get_text (entry)));
526 conn = camel_ews_store_ref_connection (ews_store);
527
528 if (!conn) {
529 e_notice (dialog, GTK_MESSAGE_ERROR, "%s", _("Cannot search for user when the account is offline"));
530 } else if (e_ews_search_user_modal (GTK_WINDOW (dialog), conn, text, &display_name, &email)) {
531 if (display_name && email && *email) {
532 gtk_entry_set_text (entry, display_name);
533 g_object_set_data_full (G_OBJECT (entry), STR_EWS_DIRECT_EMAIL, g_strdup (email), g_free);
534 }
535 }
536
537 g_free (text);
538 g_free (display_name);
539 g_free (email);
540 g_object_unref (ews_store);
541 g_clear_object (&conn);
542 }
543
544 static gint
sort_accounts_by_display_name_cb(gconstpointer ptr1,gconstpointer ptr2)545 sort_accounts_by_display_name_cb (gconstpointer ptr1,
546 gconstpointer ptr2)
547 {
548 CamelService *service1 = (CamelService *) ptr1;
549 CamelService *service2 = (CamelService *) ptr2;
550
551 return g_utf8_collate (camel_service_get_display_name (service1), camel_service_get_display_name (service2));
552 }
553
554 static GtkWidget *
create_accounts_combo(CamelSession * session,EClientCache * client_cache,CamelStore * store)555 create_accounts_combo (CamelSession *session,
556 EClientCache *client_cache,
557 CamelStore *store)
558 {
559 GtkListStore *list_store;
560 GtkTreeIter iter;
561 GtkComboBox *combo_box;
562 ESourceRegistry *registry;
563 GList *services, *link, *accounts = NULL;
564 GtkCellRenderer *renderer;
565
566 list_store = gtk_list_store_new (3,
567 G_TYPE_STRING, /* COLUMN_UID - UID of the CamelEwsStore */
568 G_TYPE_STRING, /* COLUMN_DISPLAY_NAME */
569 CAMEL_TYPE_EWS_STORE); /* COLUMN_STORE */
570
571 registry = e_client_cache_ref_registry (client_cache);
572 services = camel_session_list_services (session);
573
574 for (link = services; link; link = g_list_next (link)) {
575 CamelService *service = link->data;
576
577 if (CAMEL_IS_EWS_STORE (service)) {
578 ESource *source;
579
580 source = e_source_registry_ref_source (registry, camel_service_get_uid (service));
581 if (source && e_source_registry_check_enabled (registry, source)) {
582 accounts = g_list_prepend (accounts, service);
583 }
584
585 g_clear_object (&source);
586 }
587 }
588
589 accounts = g_list_sort (accounts, sort_accounts_by_display_name_cb);
590
591 for (link = accounts; link; link = g_list_next (link)) {
592 CamelService *service = link->data;
593
594 gtk_list_store_append (list_store, &iter);
595 gtk_list_store_set (list_store, &iter,
596 COLUMN_UID, camel_service_get_uid (service),
597 COLUMN_DISPLAY_NAME, camel_service_get_display_name (service),
598 COLUMN_STORE, service,
599 -1);
600 }
601
602 g_list_free_full (services, g_object_unref);
603 g_list_free (accounts);
604 g_clear_object (®istry);
605
606 combo_box = GTK_COMBO_BOX (gtk_combo_box_new_with_model (GTK_TREE_MODEL (list_store)));
607 g_object_unref (list_store);
608
609 renderer = gtk_cell_renderer_text_new ();
610 gtk_cell_layout_pack_start (GTK_CELL_LAYOUT (combo_box), renderer, TRUE);
611 gtk_cell_layout_set_attributes (GTK_CELL_LAYOUT (combo_box), renderer, "text", COLUMN_DISPLAY_NAME, NULL);
612
613 gtk_combo_box_set_id_column (combo_box, COLUMN_UID);
614 if (store)
615 gtk_combo_box_set_active_id (combo_box, camel_service_get_uid (CAMEL_SERVICE (store)));
616 else if (accounts)
617 gtk_combo_box_set_active (combo_box, 0);
618
619 return GTK_WIDGET (combo_box);
620 }
621
622 /* Opens dialog to subscribe to folders of other
623 * users in the given store */
624 void
e_ews_subscribe_foreign_folder(GtkWindow * parent,CamelSession * session,CamelStore * store,EClientCache * client_cache)625 e_ews_subscribe_foreign_folder (GtkWindow *parent,
626 CamelSession *session,
627 CamelStore *store,
628 EClientCache *client_cache)
629 {
630 ENameSelector *name_selector;
631 ENameSelectorModel *name_selector_model;
632 ENameSelectorDialog *name_selector_dialog;
633 GObject *dialog;
634 GtkWidget *content;
635 GtkWidget *label, *widget, *entry, *check, *accounts_combo;
636 GtkGrid *grid;
637 GtkComboBoxText *combo_text;
638 gint row;
639
640 g_return_if_fail (session != NULL);
641 if (store)
642 g_return_if_fail (CAMEL_IS_EWS_STORE (store));
643 g_return_if_fail (E_IS_CLIENT_CACHE (client_cache));
644
645 dialog = G_OBJECT (gtk_dialog_new_with_buttons (
646 _("Subscribe to folder of other EWS user…"),
647 parent,
648 GTK_DIALOG_DESTROY_WITH_PARENT,
649 GTK_STOCK_CLOSE, GTK_RESPONSE_CLOSE,
650 GTK_STOCK_OK, GTK_RESPONSE_OK,
651 NULL));
652
653 g_signal_connect (dialog, "response", G_CALLBACK (subscribe_foreign_response_cb), NULL);
654
655 content = gtk_dialog_get_content_area (GTK_DIALOG (dialog));
656
657 grid = GTK_GRID (gtk_grid_new ());
658 gtk_grid_set_row_homogeneous (grid, FALSE);
659 gtk_grid_set_row_spacing (grid, 6);
660 gtk_grid_set_column_homogeneous (grid, FALSE);
661 gtk_grid_set_column_spacing (grid, 6);
662 gtk_container_set_border_width (GTK_CONTAINER (grid), 12);
663 gtk_container_add (GTK_CONTAINER (content), GTK_WIDGET (grid));
664
665 row = 0;
666
667 label = gtk_label_new (_("Account:"));
668 g_object_set (
669 G_OBJECT (label),
670 "hexpand", FALSE,
671 "vexpand", FALSE,
672 "xalign", 0.0,
673 "halign", GTK_ALIGN_START,
674 NULL);
675
676 widget = create_accounts_combo (session, client_cache, store);
677 g_object_set (
678 G_OBJECT (widget),
679 "hexpand", TRUE,
680 "vexpand", FALSE,
681 "halign", GTK_ALIGN_START,
682 NULL);
683 accounts_combo = widget;
684
685 gtk_grid_attach (grid, label, 0, row, 1, 1);
686 gtk_grid_attach (grid, widget, 1, row, 2, 1);
687
688 row++;
689
690 name_selector = e_name_selector_new (client_cache);
691 name_selector_model = e_name_selector_peek_model (name_selector);
692 e_name_selector_model_add_section (name_selector_model, "User", _("User"), NULL);
693 name_selector_dialog = e_name_selector_peek_dialog (name_selector);
694 g_signal_connect (name_selector_dialog, "response", G_CALLBACK (gtk_widget_hide), name_selector);
695 e_name_selector_load_books (name_selector);
696
697 g_object_set_data_full (dialog, "e-ews-name-selector", name_selector, g_object_unref);
698
699 label = gtk_label_new_with_mnemonic (_("_User:"));
700 g_object_set (
701 G_OBJECT (label),
702 "hexpand", FALSE,
703 "vexpand", FALSE,
704 "xalign", 0.0,
705 NULL);
706
707 entry = GTK_WIDGET (e_name_selector_peek_section_entry (name_selector, "User"));
708 g_object_set (
709 G_OBJECT (entry),
710 "hexpand", TRUE,
711 "vexpand", FALSE,
712 NULL);
713
714 widget = gtk_button_new_with_mnemonic (_("C_hoose…"));
715 g_object_set (
716 G_OBJECT (entry),
717 "hexpand", TRUE,
718 "vexpand", FALSE,
719 NULL);
720
721 gtk_label_set_mnemonic_widget (GTK_LABEL (label), entry);
722 g_signal_connect (widget, "clicked", G_CALLBACK (pick_gal_user_clicked_cb), dialog);
723
724 gtk_grid_attach (grid, label, 0, row, 1, 1);
725 gtk_grid_attach (grid, entry, 1, row, 1, 1);
726 gtk_grid_attach (grid, widget, 2, row, 1, 1);
727
728 row++;
729
730 label = gtk_label_new_with_mnemonic (_("_Folder name:"));
731 g_object_set (
732 G_OBJECT (label),
733 "hexpand", FALSE,
734 "vexpand", FALSE,
735 "xalign", 0.0,
736 NULL);
737
738 widget = GTK_WIDGET (
739 g_object_new (gtk_combo_box_text_get_type (),
740 "has-entry", TRUE,
741 "entry-text-column", 0,
742 "hexpand", TRUE,
743 "vexpand", FALSE,
744 NULL));
745
746 combo_text = GTK_COMBO_BOX_TEXT (widget);
747 gtk_combo_box_text_append_text (combo_text, _("Inbox"));
748 gtk_combo_box_text_append_text (combo_text, _("Contacts"));
749 gtk_combo_box_text_append_text (combo_text, _("Calendar"));
750 gtk_combo_box_text_append_text (combo_text, _("Free/Busy as Calendar"));
751 gtk_combo_box_text_append_text (combo_text, _("Memos"));
752 gtk_combo_box_text_append_text (combo_text, _("Tasks"));
753 gtk_combo_box_set_active (GTK_COMBO_BOX (combo_text), 0);
754
755 gtk_label_set_mnemonic_widget (GTK_LABEL (label), widget);
756 gtk_grid_attach (grid, label, 0, row, 1, 1);
757 gtk_grid_attach (grid, widget, 1, row, 2, 1);
758
759 row++;
760
761 check = gtk_check_button_new_with_mnemonic (_("Include _subfolders"));
762 gtk_grid_attach (grid, check, 1, row, 2, 1);
763
764 /* remember widgets for later use */
765 g_object_set_data (dialog, STR_ACCOUNTS_COMBO, accounts_combo);
766 g_object_set_data (dialog, STR_USER_NAME_SELECTOR_ENTRY, entry);
767 g_object_set_data (dialog, STR_FOLDER_NAME_COMBO, widget);
768 g_object_set_data (dialog, STR_SUBFOLDERS_CHECK, check);
769
770 g_object_set_data_full (dialog, STR_EWS_CAMEL_SESSION, g_object_ref (session), g_object_unref);
771
772 g_signal_connect_swapped (entry, "changed", G_CALLBACK (name_entry_changed_cb), dialog);
773 g_signal_connect_swapped (combo_text, "changed", G_CALLBACK (folder_name_combo_changed_cb), dialog);
774 g_signal_connect_swapped (accounts_combo, "changed", G_CALLBACK (name_entry_changed_cb), dialog);
775
776 name_entry_changed_cb (dialog);
777
778 gtk_widget_show_all (content);
779 gtk_widget_show (GTK_WIDGET (dialog));
780 }
781
782 gboolean
e_ews_subscribe_foreign_folder_resolve_name_sync(EEwsConnection * cnc,const gchar * name,gchar ** out_display_name,gchar ** out_email_address,GCancellable * cancellable,GError ** error)783 e_ews_subscribe_foreign_folder_resolve_name_sync (EEwsConnection *cnc,
784 const gchar *name,
785 gchar **out_display_name,
786 gchar **out_email_address,
787 GCancellable *cancellable,
788 GError **error)
789 {
790 GSList *mailboxes = NULL;
791 EwsMailbox *mailbox = NULL;
792 gboolean includes_last_item = FALSE;
793 GError *local_error = NULL;
794
795 if (!e_ews_connection_resolve_names_sync (cnc, G_PRIORITY_DEFAULT,
796 name, EWS_SEARCH_AD, NULL, FALSE,
797 &mailboxes, NULL, &includes_last_item,
798 cancellable, &local_error)) {
799 if (g_error_matches (local_error, EWS_CONNECTION_ERROR, EWS_CONNECTION_ERROR_NAMERESOLUTIONNORESULTS) ||
800 g_error_matches (local_error, EWS_CONNECTION_ERROR, EWS_CONNECTION_ERROR_NAMERESOLUTIONNOMAILBOX)) {
801 g_clear_error (&local_error);
802 mailboxes = NULL;
803 } else {
804 if (local_error)
805 g_propagate_error (error, local_error);
806 return FALSE;
807 }
808 }
809
810 if (mailboxes) {
811 /* is there only one result? */
812 if (!mailboxes->next) {
813 mailbox = mailboxes->data;
814 } else {
815 GSList *iter;
816
817 for (iter = mailboxes; iter; iter = iter->next) {
818 EwsMailbox *mb = iter->data;
819
820 if (!mb)
821 continue;
822
823 if (mb->name && g_utf8_collate (mb->name, name) == 0) {
824 mailbox = mb;
825 break;
826 }
827 }
828 }
829
830 if (mailbox) {
831 if (out_display_name)
832 *out_display_name = g_strdup (mailbox->name);
833
834 if (out_email_address)
835 *out_email_address = g_strdup (mailbox->email);
836 }
837
838 g_slist_free_full (mailboxes, (GDestroyNotify) e_ews_mailbox_free);
839
840 if (!mailbox) {
841 g_set_error (
842 error, EWS_CONNECTION_ERROR, EWS_CONNECTION_ERROR_ITEMNOTFOUND,
843 _("User name “%s” is ambiguous, specify it more precisely, please"), name);
844 return FALSE;
845 }
846 }
847
848 return TRUE;
849 }
850
851 gboolean
e_ews_subscrive_foreign_folder_subscribe_sync(CamelEwsStore * ews_store,EEwsFolder * folder,const gchar * user_display_name,const gchar * user_email,const gchar * fallback_folder_name,gboolean include_subfolders,GCancellable * cancellable,GError ** error)852 e_ews_subscrive_foreign_folder_subscribe_sync (CamelEwsStore *ews_store,
853 EEwsFolder *folder,
854 const gchar *user_display_name,
855 const gchar *user_email,
856 const gchar *fallback_folder_name,
857 gboolean include_subfolders,
858 GCancellable *cancellable,
859 GError **error)
860 {
861 gchar *folder_name;
862 const gchar *base_username, *base_foldername;
863 CamelSettings *settings;
864 CamelEwsSettings *ews_settings;
865 ESourceRegistry *registry = NULL;
866 CamelSession *session;
867 EEwsFolderType folder_type;
868 gboolean success;
869
870 folder_type = e_ews_folder_get_folder_type (folder);
871 base_username = user_display_name ? user_display_name : user_email;
872 base_foldername = e_ews_folder_get_name (folder) ? e_ews_folder_get_name (folder) : fallback_folder_name;
873
874 /* Translators: This is used to name foreign folder.
875 * The first '%s' is replaced with user name to whom the folder belongs,
876 * the second '%s' is replaced with folder name.
877 * Example result: "John Smith — Calendar"
878 */
879 folder_name = g_strdup_printf (C_("ForeignFolder", "%s — %s"), base_username, base_foldername);
880 if (folder_type != E_EWS_FOLDER_TYPE_MAILBOX)
881 e_ews_folder_set_name (folder, folder_name);
882
883 settings = camel_service_ref_settings (CAMEL_SERVICE (ews_store));
884 ews_settings = CAMEL_EWS_SETTINGS (settings);
885 session = camel_service_ref_session (CAMEL_SERVICE (ews_store));
886 if (E_IS_MAIL_SESSION (session))
887 registry = e_mail_session_get_registry (E_MAIL_SESSION (session));
888
889 success = (folder_type == E_EWS_FOLDER_TYPE_MAILBOX &&
890 !add_foreign_folder_to_camel (ews_store,
891 user_email,
892 folder,
893 include_subfolders,
894 base_username,
895 base_foldername,
896 error)) ||
897 (folder_type != E_EWS_FOLDER_TYPE_MAILBOX && !e_ews_folder_utils_add_as_esource (registry,
898 camel_ews_settings_get_hosturl (ews_settings),
899 camel_network_settings_get_user (CAMEL_NETWORK_SETTINGS (ews_settings)),
900 folder,
901 (include_subfolders ? E_EWS_ESOURCE_FLAG_INCLUDE_SUBFOLDERS : 0) | E_EWS_ESOURCE_FLAG_OFFLINE_SYNC,
902 0,
903 cancellable,
904 error));
905
906 g_free (folder_name);
907 g_object_unref (session);
908 g_object_unref (settings);
909
910 return success;
911 }
912