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 #include <glib/gi18n-lib.h>
12
13 #include <gtk/gtk.h>
14 #include <libedataserver/libedataserver.h>
15 #include <libedataserverui/libedataserverui.h>
16
17 #include <e-util/e-util.h>
18 #include <mail/em-folder-tree.h>
19 #include <mail/em-folder-utils.h>
20 #include <libemail-engine/libemail-engine.h>
21 #include <shell/e-shell.h>
22 #include <shell/e-shell-sidebar.h>
23 #include <shell/e-shell-view.h>
24 #include <shell/e-shell-window.h>
25
26 #include "common/e-ews-connection.h"
27 #include "common/e-ews-connection-utils.h"
28 #include "common/e-source-ews-folder.h"
29
30 #include "e-ews-edit-folder-permissions.h"
31
32 #include "camel/camel-ews-store.h"
33 #include "camel/camel-ews-store-summary.h"
34
35 #include "e-ews-config-utils.h"
36 #include "e-ews-search-user.h"
37 #include "e-ews-subscribe-foreign-folder.h"
38
39 struct RunWithFeedbackData
40 {
41 GtkWindow *parent;
42 GtkWidget *dialog;
43 GCancellable *cancellable;
44 GObject *with_object;
45 EEwsSetupFunc thread_func;
46 EEwsSetupFunc idle_func;
47 EEwsSetupFunc finish_idle_func;
48 gpointer user_data;
49 GDestroyNotify free_user_data;
50 GError *error;
51 gboolean run_modal;
52 };
53
54 static void
free_run_with_feedback_data(gpointer ptr)55 free_run_with_feedback_data (gpointer ptr)
56 {
57 struct RunWithFeedbackData *rfd = ptr;
58
59 if (!rfd)
60 return;
61
62 if (rfd->dialog)
63 gtk_widget_destroy (rfd->dialog);
64
65 g_object_unref (rfd->cancellable);
66 g_object_unref (rfd->with_object);
67
68 if (rfd->free_user_data)
69 rfd->free_user_data (rfd->user_data);
70
71 g_clear_error (&rfd->error);
72
73 g_slice_free (struct RunWithFeedbackData, rfd);
74 }
75
76 static gboolean
run_with_feedback_idle(gpointer user_data)77 run_with_feedback_idle (gpointer user_data)
78 {
79 struct RunWithFeedbackData *rfd = user_data;
80 gboolean was_cancelled = FALSE;
81
82 g_return_val_if_fail (rfd != NULL, FALSE);
83
84 if (!g_cancellable_is_cancelled (rfd->cancellable)) {
85 if (rfd->idle_func && !rfd->error)
86 rfd->idle_func (rfd->with_object, rfd->user_data, rfd->cancellable, &rfd->error);
87
88 was_cancelled = g_cancellable_is_cancelled (rfd->cancellable);
89
90 if (rfd->dialog) {
91 gtk_widget_destroy (rfd->dialog);
92 rfd->dialog = NULL;
93 }
94 } else {
95 was_cancelled = TRUE;
96 }
97
98 if (rfd->finish_idle_func)
99 rfd->finish_idle_func (rfd->with_object, rfd->user_data, rfd->cancellable, &rfd->error);
100
101 if (!was_cancelled) {
102 if (rfd->error) {
103 g_dbus_error_strip_remote_error (rfd->error);
104
105 e_notice (rfd->parent, GTK_MESSAGE_ERROR, "%s", rfd->error->message);
106 }
107 }
108
109 free_run_with_feedback_data (rfd);
110
111 return FALSE;
112 }
113
114 static gpointer
run_with_feedback_thread(gpointer user_data)115 run_with_feedback_thread (gpointer user_data)
116 {
117 struct RunWithFeedbackData *rfd = user_data;
118
119 g_return_val_if_fail (rfd != NULL, NULL);
120 g_return_val_if_fail (rfd->thread_func != NULL, NULL);
121
122 if (!g_cancellable_is_cancelled (rfd->cancellable))
123 rfd->thread_func (rfd->with_object, rfd->user_data, rfd->cancellable, &rfd->error);
124
125 g_idle_add (run_with_feedback_idle, rfd);
126
127 return NULL;
128 }
129
130 static void
run_with_feedback_response_cb(GtkWidget * dialog,gint resonse_id,struct RunWithFeedbackData * rfd)131 run_with_feedback_response_cb (GtkWidget *dialog,
132 gint resonse_id,
133 struct RunWithFeedbackData *rfd)
134 {
135 g_return_if_fail (rfd != NULL);
136
137 rfd->dialog = NULL;
138
139 g_cancellable_cancel (rfd->cancellable);
140
141 gtk_widget_destroy (dialog);
142 }
143
144 static void
e_ews_config_utils_run_in_thread_with_feedback_general(GtkWindow * parent,GObject * with_object,const gchar * description,EEwsSetupFunc thread_func,EEwsSetupFunc idle_func,gpointer user_data,GDestroyNotify free_user_data,gboolean run_modal)145 e_ews_config_utils_run_in_thread_with_feedback_general (GtkWindow *parent,
146 GObject *with_object,
147 const gchar *description,
148 EEwsSetupFunc thread_func,
149 EEwsSetupFunc idle_func,
150 gpointer user_data,
151 GDestroyNotify free_user_data,
152 gboolean run_modal)
153 {
154 GtkWidget *dialog, *label, *content, *spinner, *box;
155 struct RunWithFeedbackData *rfd;
156
157 g_return_if_fail (with_object != NULL);
158 g_return_if_fail (description != NULL);
159 g_return_if_fail (thread_func != NULL);
160
161 dialog = gtk_dialog_new_with_buttons (
162 "",
163 parent,
164 GTK_DIALOG_MODAL,
165 GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL,
166 NULL);
167
168 box = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 6);
169
170 spinner = e_spinner_new ();
171 e_spinner_start (E_SPINNER (spinner));
172 gtk_box_pack_start (GTK_BOX (box), spinner, FALSE, FALSE, 0);
173
174 label = gtk_label_new (description);
175 gtk_box_pack_start (GTK_BOX (box), label, TRUE, TRUE, 0);
176
177 gtk_widget_show_all (box);
178
179 content = gtk_dialog_get_content_area (GTK_DIALOG (dialog));
180
181 gtk_container_add (GTK_CONTAINER (content), box);
182 gtk_container_set_border_width (GTK_CONTAINER (content), 12);
183
184 rfd = g_slice_new0 (struct RunWithFeedbackData);
185 rfd->parent = parent;
186 rfd->dialog = dialog;
187 rfd->cancellable = g_cancellable_new ();
188 rfd->with_object = g_object_ref (with_object);
189 rfd->thread_func = thread_func;
190 rfd->idle_func = idle_func;
191 rfd->finish_idle_func = NULL;
192 rfd->user_data = user_data;
193 rfd->free_user_data = free_user_data;
194 rfd->error = NULL;
195 rfd->run_modal = run_modal;
196
197 g_signal_connect (dialog, "response", G_CALLBACK (run_with_feedback_response_cb), rfd);
198
199 if (run_modal) {
200 GThread *thread;
201 GCancellable *cancellable;
202
203 cancellable = g_object_ref (rfd->cancellable);
204
205 thread = g_thread_new (NULL, run_with_feedback_thread, rfd);
206 g_thread_unref (thread);
207
208 gtk_dialog_run (GTK_DIALOG (dialog));
209
210 g_cancellable_cancel (cancellable);
211 g_object_unref (cancellable);
212 } else {
213 GThread *thread;
214
215 gtk_widget_show (dialog);
216
217 thread = g_thread_new (NULL, run_with_feedback_thread, rfd);
218 g_thread_unref (thread);
219 }
220 }
221
222 void
e_ews_config_utils_run_in_thread_with_feedback(GtkWindow * parent,GObject * with_object,const gchar * description,EEwsSetupFunc thread_func,EEwsSetupFunc idle_func,gpointer user_data,GDestroyNotify free_user_data)223 e_ews_config_utils_run_in_thread_with_feedback (GtkWindow *parent,
224 GObject *with_object,
225 const gchar *description,
226 EEwsSetupFunc thread_func,
227 EEwsSetupFunc idle_func,
228 gpointer user_data,
229 GDestroyNotify free_user_data)
230 {
231 e_ews_config_utils_run_in_thread_with_feedback_general (parent, with_object, description, thread_func, idle_func, user_data, free_user_data, FALSE);
232 }
233
234 void
e_ews_config_utils_run_in_thread_with_feedback_modal(GtkWindow * parent,GObject * with_object,const gchar * description,EEwsSetupFunc thread_func,EEwsSetupFunc idle_func,gpointer user_data,GDestroyNotify free_user_data)235 e_ews_config_utils_run_in_thread_with_feedback_modal (GtkWindow *parent,
236 GObject *with_object,
237 const gchar *description,
238 EEwsSetupFunc thread_func,
239 EEwsSetupFunc idle_func,
240 gpointer user_data,
241 GDestroyNotify free_user_data)
242 {
243 e_ews_config_utils_run_in_thread_with_feedback_general (parent, with_object, description, thread_func, idle_func, user_data, free_user_data, TRUE);
244 }
245
246 void
e_ews_config_utils_run_in_thread(GObject * with_object,EEwsSetupFunc thread_func,EEwsSetupFunc idle_func,gpointer user_data,GDestroyNotify free_user_data,GCancellable * cancellable)247 e_ews_config_utils_run_in_thread (GObject *with_object,
248 EEwsSetupFunc thread_func,
249 EEwsSetupFunc idle_func,
250 gpointer user_data,
251 GDestroyNotify free_user_data,
252 GCancellable *cancellable)
253 {
254 struct RunWithFeedbackData *rfd;
255 GThread *thread;
256
257 g_return_if_fail (with_object != NULL);
258 g_return_if_fail (thread_func != NULL);
259
260 rfd = g_slice_new0 (struct RunWithFeedbackData);
261 rfd->parent = NULL;
262 rfd->dialog = NULL;
263 rfd->cancellable = cancellable ? g_object_ref (cancellable) : g_cancellable_new ();
264 rfd->with_object = g_object_ref (with_object);
265 rfd->thread_func = thread_func;
266 rfd->idle_func = NULL;
267 rfd->finish_idle_func = idle_func;
268 rfd->user_data = user_data;
269 rfd->free_user_data = free_user_data;
270 rfd->error = NULL;
271 rfd->run_modal = FALSE;
272
273 thread = g_thread_new (NULL, run_with_feedback_thread, rfd);
274 g_thread_unref (thread);
275 }
276
277 typedef struct _TryCredentialsData {
278 CamelEwsSettings *ews_settings;
279 const gchar *connect_url;
280 EEwsConfigUtilTryCredentialsFunc try_credentials_func;
281 gpointer user_data;
282 EEwsConnection *conn;
283 } TryCredentialsData;
284
285 static gboolean
ews_config_utils_try_credentials_sync(ECredentialsPrompter * prompter,ESource * source,const ENamedParameters * credentials,gboolean * out_authenticated,gpointer user_data,GCancellable * cancellable,GError ** error)286 ews_config_utils_try_credentials_sync (ECredentialsPrompter *prompter,
287 ESource *source,
288 const ENamedParameters *credentials,
289 gboolean *out_authenticated,
290 gpointer user_data,
291 GCancellable *cancellable,
292 GError **error)
293 {
294 TryCredentialsData *data = user_data;
295 ESourceAuthenticationResult auth_result;
296 gchar *hosturl;
297 gboolean res = TRUE;
298
299 hosturl = camel_ews_settings_dup_hosturl (data->ews_settings);
300 data->conn = e_ews_connection_new (source, data->connect_url ? data->connect_url : hosturl, data->ews_settings);
301 g_free (hosturl);
302
303 e_ews_connection_update_credentials (data->conn, credentials);
304
305 if (data->try_credentials_func)
306 auth_result = data->try_credentials_func (data->conn, credentials, data->user_data, cancellable, error);
307 else
308 auth_result = e_ews_connection_try_credentials_sync (data->conn, credentials, NULL, NULL, NULL, cancellable, error);
309
310 if (auth_result == E_SOURCE_AUTHENTICATION_ACCEPTED) {
311 *out_authenticated = TRUE;
312 } else if (auth_result == E_SOURCE_AUTHENTICATION_REJECTED) {
313 *out_authenticated = FALSE;
314 g_clear_object (&data->conn);
315 g_clear_error (error);
316 } else {
317 res = FALSE;
318 g_clear_object (&data->conn);
319 }
320
321 return res;
322 }
323
324 EEwsConnection *
e_ews_config_utils_open_connection_for(ESource * source,CamelEwsSettings * ews_settings,const gchar * connect_url,EEwsConfigUtilTryCredentialsFunc try_credentials_func,gpointer user_data,GCancellable * cancellable,GError ** perror)325 e_ews_config_utils_open_connection_for (ESource *source,
326 CamelEwsSettings *ews_settings,
327 const gchar *connect_url,
328 EEwsConfigUtilTryCredentialsFunc try_credentials_func,
329 gpointer user_data,
330 GCancellable *cancellable,
331 GError **perror)
332 {
333 EEwsConnection *conn = NULL;
334 CamelNetworkSettings *network_settings;
335 GError *local_error = NULL;
336
337 g_return_val_if_fail (source != NULL, NULL);
338 g_return_val_if_fail (ews_settings != NULL, NULL);
339
340 network_settings = CAMEL_NETWORK_SETTINGS (ews_settings);
341
342 /* use the one from mailer, if there, otherwise open new */
343 conn = e_ews_connection_find (
344 connect_url && *connect_url ? connect_url : camel_ews_settings_get_hosturl (ews_settings),
345 camel_network_settings_get_user (network_settings));
346 if (conn) {
347 if (try_credentials_func &&
348 try_credentials_func (conn, NULL, user_data, cancellable, perror) != E_SOURCE_AUTHENTICATION_ACCEPTED) {
349 g_clear_object (&conn);
350 }
351 return conn;
352 }
353
354 while (!conn && !g_cancellable_is_cancelled (cancellable) && !local_error) {
355 if (e_ews_connection_utils_get_without_password (ews_settings)) {
356 ESourceAuthenticationResult result;
357 gchar *hosturl;
358
359 hosturl = camel_ews_settings_dup_hosturl (ews_settings);
360 conn = e_ews_connection_new (source, connect_url && *connect_url ? connect_url : hosturl, ews_settings);
361 g_free (hosturl);
362
363 e_ews_connection_update_credentials (conn, NULL);
364
365 if (try_credentials_func)
366 result = try_credentials_func (conn, NULL, user_data, cancellable, &local_error);
367 else
368 result = e_ews_connection_try_credentials_sync (conn, NULL, NULL, NULL, NULL, cancellable, &local_error);
369
370 if (result != E_SOURCE_AUTHENTICATION_ACCEPTED) {
371 g_clear_object (&conn);
372 if (result != E_SOURCE_AUTHENTICATION_REJECTED || local_error)
373 break;
374 }
375 }
376
377 if (!conn) {
378 EShell *shell;
379 TryCredentialsData data;
380
381 e_ews_connection_utils_force_off_ntlm_auth_check ();
382 g_clear_error (&local_error);
383
384 shell = e_shell_get_default ();
385
386 data.ews_settings = g_object_ref (ews_settings);
387 data.connect_url = connect_url && *connect_url ? connect_url : NULL;
388 data.try_credentials_func = try_credentials_func;
389 data.user_data = user_data;
390 data.conn = NULL;
391
392 e_credentials_prompter_loop_prompt_sync (e_shell_get_credentials_prompter (shell),
393 source, E_CREDENTIALS_PROMPTER_PROMPT_FLAG_ALLOW_SOURCE_SAVE,
394 ews_config_utils_try_credentials_sync, &data, cancellable, &local_error);
395
396 if (data.conn)
397 conn = g_object_ref (data.conn);
398
399 g_clear_object (&data.ews_settings);
400 g_clear_object (&data.conn);
401 }
402 }
403
404 if (local_error)
405 g_propagate_error (perror, local_error);
406
407 return conn;
408 }
409
410 enum {
411 COL_FOLDER_ICON = 0, /* G_TYPE_STRING */
412 COL_FOLDER_NAME, /* G_TYPE_STRING */
413 COL_FOLDER_SIZE, /* G_TYPE_STRING */
414 COL_FOLDER_FLAGS, /* G_TYPE_UINT */
415 N_COLUMNS
416 };
417
418 typedef struct
419 {
420 GtkDialog *dialog;
421 GtkGrid *spinner_grid;
422
423 ESourceRegistry *registry;
424 ESource *source;
425 CamelEwsSettings *ews_settings;
426 CamelEwsStore *ews_store;
427
428 GHashTable *folder_sizes;
429 GCancellable *cancellable;
430 GError *error;
431 } FolderSizeDialogData;
432
433 static gint
folder_tree_model_sort(GtkTreeModel * model,GtkTreeIter * a,GtkTreeIter * b,gpointer unused)434 folder_tree_model_sort (GtkTreeModel *model,
435 GtkTreeIter *a,
436 GtkTreeIter *b,
437 gpointer unused)
438 {
439 gchar *aname, *bname;
440 guint32 aflags, bflags;
441 gint ret = -2;
442
443 gtk_tree_model_get (
444 model, a,
445 COL_FOLDER_NAME, &aname,
446 COL_FOLDER_FLAGS, &aflags,
447 -1);
448
449 gtk_tree_model_get (
450 model, b,
451 COL_FOLDER_NAME, &bname,
452 COL_FOLDER_FLAGS, &bflags,
453 -1);
454
455 /* Inbox is always first. */
456 if ((aflags & CAMEL_FOLDER_TYPE_MASK) == CAMEL_FOLDER_TYPE_INBOX)
457 ret = -1;
458 else if ((bflags & CAMEL_FOLDER_TYPE_MASK) == CAMEL_FOLDER_TYPE_INBOX)
459 ret = 1;
460 else {
461 if (aname != NULL && bname != NULL)
462 ret = g_utf8_collate (aname, bname);
463 else if (aname == bname)
464 ret = 0;
465 else if (aname == NULL)
466 ret = -1;
467 else
468 ret = 1;
469 }
470
471 g_free (aname);
472 g_free (bname);
473
474 return ret;
475 }
476
477 static void
folder_sizes_tree_populate(GtkTreeStore * store,CamelFolderInfo * folder_info,GtkTreeIter * parent,FolderSizeDialogData * fsd)478 folder_sizes_tree_populate (GtkTreeStore *store,
479 CamelFolderInfo *folder_info,
480 GtkTreeIter *parent,
481 FolderSizeDialogData *fsd)
482 {
483 while (folder_info != NULL) {
484 GtkTreeIter iter;
485 const gchar *icon_name;
486 const gchar *folder_size;
487
488 icon_name = em_folder_utils_get_icon_name (folder_info->flags);
489 if (g_strcmp0 (icon_name, "folder") == 0) {
490 CamelFolder *folder;
491
492 folder = camel_store_get_folder_sync (
493 CAMEL_STORE (fsd->ews_store), folder_info->full_name, 0, NULL, NULL);
494
495 if (folder != NULL) {
496 if (em_utils_folder_is_drafts (fsd->registry, folder))
497 icon_name = "accessories-text-editor";
498
499 g_object_unref (folder);
500 }
501 }
502
503 folder_size = g_hash_table_lookup (fsd->folder_sizes, folder_info->full_name);
504
505 gtk_tree_store_append (store, &iter, parent);
506 gtk_tree_store_set (store, &iter,
507 COL_FOLDER_ICON, icon_name,
508 COL_FOLDER_NAME, folder_info->display_name,
509 COL_FOLDER_SIZE, folder_size,
510 COL_FOLDER_FLAGS, folder_info->flags,
511 -1);
512
513 if (folder_info->child != NULL)
514 folder_sizes_tree_populate (store, folder_info->child, &iter, fsd);
515
516 folder_info = folder_info->next;
517 }
518 }
519
520 static gboolean
ews_settings_get_folder_sizes_idle(gpointer user_data)521 ews_settings_get_folder_sizes_idle (gpointer user_data)
522 {
523 GtkWidget *widget;
524 GtkCellRenderer *renderer;
525 GtkTreeStore *tree_store;
526 GtkBox *content_area;
527 FolderSizeDialogData *fsd = user_data;
528 CamelFolderInfo *root;
529
530 g_return_val_if_fail (fsd != NULL, FALSE);
531
532 if (g_cancellable_is_cancelled (fsd->cancellable))
533 goto cleanup;
534
535 /* Hide progress bar. Set status */
536 gtk_widget_destroy (GTK_WIDGET (fsd->spinner_grid));
537
538 if (fsd->folder_sizes != NULL) {
539 GtkWidget *scrolledwindow, *tree_view;
540
541 scrolledwindow = gtk_scrolled_window_new (NULL, NULL);
542 gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (scrolledwindow),
543 GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC);
544 gtk_widget_show (scrolledwindow);
545
546 /* Tree View */
547 tree_view = gtk_tree_view_new ();
548 renderer = gtk_cell_renderer_pixbuf_new ();
549 gtk_tree_view_insert_column_with_attributes (
550 GTK_TREE_VIEW (tree_view),
551 -1,
552 NULL,
553 renderer,
554 "icon-name",
555 COL_FOLDER_ICON,
556 NULL);
557
558 renderer = gtk_cell_renderer_text_new ();
559 gtk_tree_view_insert_column_with_attributes (
560 GTK_TREE_VIEW (tree_view),
561 -1,
562 _("Folder"),
563 renderer,
564 "text",
565 COL_FOLDER_NAME,
566 NULL);
567
568 renderer = gtk_cell_renderer_text_new ();
569 gtk_tree_view_insert_column_with_attributes (
570 GTK_TREE_VIEW (tree_view),
571 -1,
572 _("Size"),
573 renderer,
574 "text",
575 COL_FOLDER_SIZE,
576 NULL);
577
578 /* Model for TreeView */
579 tree_store = gtk_tree_store_new (
580 N_COLUMNS,
581 /* COL_FOLDER_ICON */ G_TYPE_STRING,
582 /* COL_FOLDER_NAME */ G_TYPE_STRING,
583 /* COL_FOLDER_SIZE */ G_TYPE_STRING,
584 /* COL_FOLDER_FLAGS */ G_TYPE_UINT);
585
586 gtk_tree_sortable_set_default_sort_func (
587 GTK_TREE_SORTABLE (tree_store),
588 folder_tree_model_sort, NULL, NULL);
589
590 gtk_tree_sortable_set_sort_column_id (
591 GTK_TREE_SORTABLE (tree_store),
592 GTK_TREE_SORTABLE_DEFAULT_SORT_COLUMN_ID,
593 GTK_SORT_ASCENDING);
594
595 gtk_tree_view_set_model (GTK_TREE_VIEW (tree_view), GTK_TREE_MODEL (tree_store));
596
597 root = camel_store_get_folder_info_sync (
598 CAMEL_STORE (fsd->ews_store), NULL,
599 CAMEL_STORE_FOLDER_INFO_RECURSIVE,
600 NULL, NULL);
601
602 folder_sizes_tree_populate (tree_store, root, NULL, fsd);
603
604 camel_folder_info_free (root);
605
606 gtk_tree_view_expand_all (GTK_TREE_VIEW (tree_view));
607 gtk_container_add (GTK_CONTAINER (scrolledwindow), tree_view);
608 widget = scrolledwindow;
609 } else if (fsd->error) {
610 gchar *msg = g_strconcat (_("Unable to retrieve folder size information"), "\n",
611 fsd->error->message, NULL);
612 widget = gtk_label_new (msg);
613 g_free (msg);
614 } else {
615 widget = gtk_label_new (_("Unable to retrieve folder size information"));
616 }
617
618 gtk_widget_show_all (widget);
619
620 /* Pack into content_area */
621 content_area = GTK_BOX (gtk_dialog_get_content_area (fsd->dialog));
622 gtk_box_pack_start (content_area, widget, TRUE, TRUE, 6);
623
624 cleanup:
625 g_hash_table_destroy (fsd->folder_sizes);
626 g_object_unref (fsd->registry);
627 g_object_unref (fsd->source);
628 g_object_unref (fsd->ews_settings);
629 g_object_unref (fsd->ews_store);
630 g_object_unref (fsd->cancellable);
631 g_clear_error (&fsd->error);
632 g_slice_free (FolderSizeDialogData, fsd);
633
634 return FALSE;
635 }
636
637 static gpointer
ews_settings_get_folder_sizes_thread(gpointer user_data)638 ews_settings_get_folder_sizes_thread (gpointer user_data)
639 {
640 FolderSizeDialogData *fsd = user_data;
641 EEwsConnection *cnc;
642
643 g_return_val_if_fail (fsd != NULL, NULL);
644
645 cnc = e_ews_config_utils_open_connection_for (
646 fsd->source,
647 fsd->ews_settings,
648 NULL, NULL, NULL,
649 fsd->cancellable,
650 &fsd->error);
651
652 if (cnc) {
653 EEwsAdditionalProps *add_props;
654 EEwsExtendedFieldURI *ext_uri;
655 GSList *ids, *l, *folders_ids = NULL, *folders_list = NULL;
656
657 fsd->folder_sizes = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, g_free);
658
659 /* Use MAPI property to retrieve folder size */
660 add_props = e_ews_additional_props_new ();
661 ext_uri = e_ews_extended_field_uri_new ();
662 ext_uri->prop_tag = g_strdup_printf ("%d", 0x0e08); /* Folder size property tag */
663 ext_uri->prop_type = g_strdup ("Integer");
664 add_props->extended_furis = g_slist_prepend (add_props->extended_furis, ext_uri);
665
666 ids = camel_ews_store_summary_get_folders (fsd->ews_store->summary, NULL, FALSE);
667 for (l = ids; l != NULL; l = l->next) {
668 EwsFolderId *fid;
669 fid = e_ews_folder_id_new (l->data, NULL, FALSE);
670 folders_ids = g_slist_prepend (folders_ids, fid);
671 }
672 folders_ids = g_slist_reverse (folders_ids);
673
674 e_ews_connection_get_folder_sync (
675 cnc, EWS_PRIORITY_MEDIUM, "Default",
676 add_props, folders_ids, &folders_list,
677 fsd->cancellable, &fsd->error);
678
679 for (l = folders_list; l != NULL; l = l->next) {
680 const EEwsFolder *folder = l->data;
681 const EwsFolderId *folder_id;
682 gchar *folder_full_name;
683 gchar *folder_size;
684
685 if (!folder || e_ews_folder_is_error (folder))
686 continue;
687
688 folder_id = e_ews_folder_get_id (folder);
689 if (!folder_id)
690 continue;
691
692 folder_full_name = camel_ews_store_summary_get_folder_full_name (
693 fsd->ews_store->summary, folder_id->id, NULL);
694 folder_size = g_format_size (e_ews_folder_get_size (folder));
695
696 g_hash_table_insert (fsd->folder_sizes, folder_full_name, folder_size);
697 }
698
699 g_slist_free_full (folders_list, g_object_unref);
700 g_slist_free_full (folders_ids, (GDestroyNotify) e_ews_folder_id_free);
701 g_slist_free_full (ids, g_free);
702 e_ews_additional_props_free (add_props);
703 g_object_unref (cnc);
704 }
705
706 g_idle_add (ews_settings_get_folder_sizes_idle, fsd);
707
708 return NULL;
709 }
710
711 static void
folder_sizes_dialog_response_cb(GObject * dialog,gint response_id,gpointer data)712 folder_sizes_dialog_response_cb (GObject *dialog,
713 gint response_id,
714 gpointer data)
715 {
716 GCancellable *cancellable = data;
717
718 g_cancellable_cancel (cancellable);
719 g_object_unref (cancellable);
720
721 gtk_widget_destroy (GTK_WIDGET (dialog));
722 }
723
724 void
e_ews_config_utils_run_folder_sizes_dialog(GtkWindow * parent,ESourceRegistry * registry,ESource * source,CamelEwsStore * ews_store)725 e_ews_config_utils_run_folder_sizes_dialog (GtkWindow *parent,
726 ESourceRegistry *registry,
727 ESource *source,
728 CamelEwsStore *ews_store)
729 {
730 GtkBox *content_area;
731 GtkWidget *spinner, *alignment, *dialog;
732 GtkWidget *spinner_label;
733 GCancellable *cancellable;
734 GThread *thread;
735 FolderSizeDialogData *fsd;
736
737 g_return_if_fail (ews_store != NULL);
738
739 cancellable = g_cancellable_new ();
740
741 dialog = gtk_dialog_new_with_buttons (
742 _("Folder Sizes"),
743 parent,
744 GTK_DIALOG_DESTROY_WITH_PARENT,
745 _("_Close"), GTK_RESPONSE_ACCEPT,
746 NULL);
747
748 g_signal_connect (dialog, "response", G_CALLBACK (folder_sizes_dialog_response_cb), cancellable);
749
750 fsd = g_slice_new0 (FolderSizeDialogData);
751 fsd->dialog = GTK_DIALOG (dialog);
752
753 gtk_window_set_default_size (GTK_WINDOW (fsd->dialog), 250, 300);
754
755 content_area = GTK_BOX (gtk_dialog_get_content_area (fsd->dialog));
756
757 spinner = e_spinner_new ();
758 e_spinner_start (E_SPINNER (spinner));
759 spinner_label = gtk_label_new (_("Fetching folder list…"));
760
761 fsd->spinner_grid = GTK_GRID (gtk_grid_new ());
762 gtk_grid_set_column_spacing (fsd->spinner_grid, 6);
763 gtk_grid_set_column_homogeneous (fsd->spinner_grid, FALSE);
764 gtk_orientable_set_orientation (GTK_ORIENTABLE (fsd->spinner_grid), GTK_ORIENTATION_HORIZONTAL);
765
766 alignment = gtk_alignment_new (1.0, 0.5, 0.0, 1.0);
767 gtk_container_add (GTK_CONTAINER (alignment), spinner);
768 gtk_misc_set_alignment (GTK_MISC (spinner_label), 0.0, 0.5);
769
770 gtk_container_add (GTK_CONTAINER (fsd->spinner_grid), alignment);
771 gtk_container_add (GTK_CONTAINER (fsd->spinner_grid), spinner_label);
772
773 /* Pack the TreeView into dialog's content area */
774 gtk_box_pack_start (content_area, GTK_WIDGET (fsd->spinner_grid), TRUE, TRUE, 6);
775 gtk_widget_show_all (GTK_WIDGET (fsd->dialog));
776
777 fsd->registry = g_object_ref (registry);
778 fsd->source = g_object_ref (source);
779 fsd->ews_store = g_object_ref (ews_store);
780 fsd->ews_settings = CAMEL_EWS_SETTINGS (camel_service_ref_settings (CAMEL_SERVICE (ews_store)));
781 fsd->cancellable = g_object_ref (cancellable);
782
783 thread = g_thread_new (NULL, ews_settings_get_folder_sizes_thread, fsd);
784 g_thread_unref (thread);
785
786 /* Start the dialog */
787 gtk_widget_show (GTK_WIDGET (dialog));
788 }
789
790 static void
action_global_subscribe_foreign_folder_cb(GtkAction * action,EShellView * shell_view)791 action_global_subscribe_foreign_folder_cb (GtkAction *action,
792 EShellView *shell_view)
793 {
794 EShell *shell;
795 EShellBackend *shell_backend;
796 EShellWindow *shell_window;
797 EClientCache *client_cache;
798 CamelSession *session = NULL;
799
800 g_return_if_fail (E_IS_SHELL_VIEW (shell_view));
801
802 shell_window = e_shell_view_get_shell_window (shell_view);
803 shell = e_shell_window_get_shell (shell_window);
804 shell_backend = e_shell_get_backend_by_name (shell, "mail");
805
806 if (shell_backend)
807 g_object_get (G_OBJECT (shell_backend), "session", &session, NULL);
808
809 if (!session)
810 return;
811
812 client_cache = e_shell_get_client_cache (shell);
813
814 e_ews_subscribe_foreign_folder (GTK_WINDOW (shell_window), session, NULL, client_cache);
815
816 g_object_unref (session);
817 }
818
819 static GtkActionEntry global_ews_entries[] = {
820 { "ews-global-subscribe-foreign-folder",
821 NULL,
822 N_("Subscribe to folder of other EWS user…"),
823 NULL,
824 NULL, /* XXX Add a tooltip! */
825 G_CALLBACK (action_global_subscribe_foreign_folder_cb) }
826 };
827
828 static gboolean
ews_ui_has_ews_account(EShellView * shell_view,CamelSession * in_session)829 ews_ui_has_ews_account (EShellView *shell_view,
830 CamelSession *in_session)
831 {
832 CamelSession *session = in_session;
833 EShell *shell;
834 gboolean has_any = FALSE;
835
836 g_return_val_if_fail (E_IS_SHELL_VIEW (shell_view), FALSE);
837 if (in_session)
838 g_return_val_if_fail (CAMEL_IS_SESSION (in_session), FALSE);
839
840 shell = e_shell_window_get_shell (e_shell_view_get_shell_window (shell_view));
841
842 if (!session) {
843 EShellBackend *shell_backend;
844
845 shell_backend = e_shell_get_backend_by_name (shell, "mail");
846
847 if (shell_backend) {
848 g_object_get (G_OBJECT (shell_backend), "session", &session, NULL);
849 }
850 }
851
852 if (session) {
853 ESourceRegistry *registry;
854 GList *services, *link;
855
856 registry = e_shell_get_registry (shell);
857 services = camel_session_list_services (session);
858
859 for (link = services; link && !has_any; link = g_list_next (link)) {
860 CamelService *service = link->data;
861
862 if (CAMEL_IS_EWS_STORE (service)) {
863 ESource *source;
864
865 source = e_source_registry_ref_source (registry, camel_service_get_uid (service));
866 has_any = source && e_source_registry_check_enabled (registry, source);
867
868 g_clear_object (&source);
869 }
870 }
871
872 g_list_free_full (services, g_object_unref);
873 }
874
875 if (session && session != in_session)
876 g_object_unref (session);
877
878 return has_any;
879 }
880
881 static gboolean
get_ews_store_from_folder_tree(EShellView * shell_view,gchar ** pfolder_path,CamelStore ** pstore)882 get_ews_store_from_folder_tree (EShellView *shell_view,
883 gchar **pfolder_path,
884 CamelStore **pstore)
885 {
886 EShellSidebar *shell_sidebar;
887 EMFolderTree *folder_tree;
888 gchar *selected_path = NULL;
889 CamelStore *selected_store = NULL;
890 gboolean found = FALSE;
891
892 /* Get hold of Folder Tree */
893 shell_sidebar = e_shell_view_get_shell_sidebar (shell_view);
894 g_object_get (shell_sidebar, "folder-tree", &folder_tree, NULL);
895 if (em_folder_tree_get_selected (folder_tree, &selected_store, &selected_path) ||
896 em_folder_tree_store_root_selected (folder_tree, &selected_store)) {
897 if (selected_store) {
898 CamelProvider *provider = camel_service_get_provider (CAMEL_SERVICE (selected_store));
899
900 if (provider && g_ascii_strcasecmp (provider->protocol, "ews") == 0) {
901 found = TRUE;
902
903 if (pstore)
904 *pstore = g_object_ref (selected_store);
905
906 if (pfolder_path)
907 *pfolder_path = selected_path;
908 else
909 g_free (selected_path);
910
911 selected_path = NULL;
912 }
913
914 g_object_unref (selected_store);
915 }
916
917 g_free (selected_path);
918 }
919
920 g_object_unref (folder_tree);
921
922 return found;
923 }
924
925 static void
action_folder_sizes_cb(GtkAction * action,EShellView * shell_view)926 action_folder_sizes_cb (GtkAction *action,
927 EShellView *shell_view)
928 {
929 GtkWindow *parent;
930 CamelSession *session;
931 CamelStore *store = NULL;
932 ESourceRegistry *registry;
933 ESource *source;
934
935 if (!get_ews_store_from_folder_tree (shell_view, NULL, &store))
936 return;
937
938 g_return_if_fail (store != NULL);
939
940 parent = GTK_WINDOW (e_shell_view_get_shell_window (shell_view));
941
942 session = camel_service_ref_session (CAMEL_SERVICE (store));
943 registry = e_mail_session_get_registry (E_MAIL_SESSION (session));
944 source = e_source_registry_ref_source (registry, camel_service_get_uid (CAMEL_SERVICE (store)));
945
946 e_ews_config_utils_run_folder_sizes_dialog (parent, registry, source, CAMEL_EWS_STORE (store));
947
948 g_object_unref (source);
949 g_object_unref (session);
950 g_object_unref (store);
951 }
952
953 static void
action_subscribe_foreign_folder_cb(GtkAction * action,EShellView * shell_view)954 action_subscribe_foreign_folder_cb (GtkAction *action,
955 EShellView *shell_view)
956 {
957 GtkWindow *parent;
958 EShell *shell;
959 EShellBackend *backend;
960 EClientCache *client_cache;
961 CamelSession *session = NULL;
962 CamelStore *store = NULL;
963
964 if (!get_ews_store_from_folder_tree (shell_view, NULL, &store))
965 return;
966
967 parent = GTK_WINDOW (e_shell_view_get_shell_window (shell_view));
968 backend = e_shell_view_get_shell_backend (shell_view);
969 g_object_get (G_OBJECT (backend), "session", &session, NULL);
970
971 shell = e_shell_backend_get_shell (backend);
972 client_cache = e_shell_get_client_cache (shell);
973
974 e_ews_subscribe_foreign_folder (parent, session, store, client_cache);
975
976 g_object_unref (session);
977 g_object_unref (store);
978 }
979
980 static void
action_folder_permissions_mail_cb(GtkAction * action,EShellView * shell_view)981 action_folder_permissions_mail_cb (GtkAction *action,
982 EShellView *shell_view)
983 {
984 EShell *shell;
985 EShellWindow *shell_window;
986 ESourceRegistry *registry;
987 GtkWindow *parent;
988 CamelStore *store = NULL;
989 CamelEwsStore *ews_store;
990 EwsFolderId *folder_id = NULL;
991 gchar *folder_path = NULL;
992
993 if (!get_ews_store_from_folder_tree (shell_view, &folder_path, &store))
994 return;
995
996 ews_store = CAMEL_EWS_STORE (store);
997 g_return_if_fail (ews_store != NULL);
998
999 shell_window = e_shell_view_get_shell_window (shell_view);
1000 parent = GTK_WINDOW (shell_window);
1001 shell = e_shell_window_get_shell (shell_window);
1002 registry = e_shell_get_registry (shell);
1003
1004 if (folder_path && *folder_path) {
1005 gchar *str_folder_id = NULL;
1006
1007 str_folder_id = camel_ews_store_summary_get_folder_id_from_name (ews_store->summary, folder_path);
1008 if (!str_folder_id) {
1009 e_notice (parent, GTK_MESSAGE_ERROR, _("Cannot edit permissions of folder “%s”, choose other folder."), folder_path);
1010 } else {
1011 gchar *str_change_key;
1012
1013 str_change_key = camel_ews_store_summary_get_change_key (
1014 ews_store->summary, str_folder_id, NULL);
1015
1016 folder_id = e_ews_folder_id_new (str_folder_id, str_change_key, FALSE);
1017
1018 g_free (str_change_key);
1019 }
1020
1021 g_free (str_folder_id);
1022 } else {
1023 g_clear_pointer (&folder_path, g_free);
1024
1025 folder_id = e_ews_folder_id_new ("msgfolderroot", NULL, TRUE);
1026 }
1027
1028 if (folder_id) {
1029 ESource *source;
1030 CamelService *service;
1031 CamelSettings *settings;
1032 const gchar *uid;
1033
1034 service = CAMEL_SERVICE (store);
1035 uid = camel_service_get_uid (service);
1036 source = e_source_registry_ref_source (registry, uid);
1037 g_return_if_fail (source != NULL);
1038
1039 settings = camel_service_ref_settings (service);
1040
1041 e_ews_edit_folder_permissions (
1042 parent,
1043 registry,
1044 source,
1045 CAMEL_EWS_SETTINGS (settings),
1046 camel_service_get_display_name (service),
1047 folder_path ? folder_path : camel_service_get_display_name (service),
1048 folder_id,
1049 E_EWS_FOLDER_TYPE_MAILBOX);
1050
1051 g_object_unref (settings);
1052 g_object_unref (source);
1053 }
1054
1055 g_object_unref (store);
1056 g_free (folder_path);
1057 e_ews_folder_id_free (folder_id);
1058 }
1059
1060 static void
ews_ui_enable_actions(GtkActionGroup * action_group,const GtkActionEntry * entries,guint n_entries,gboolean can_show,gboolean is_online)1061 ews_ui_enable_actions (GtkActionGroup *action_group,
1062 const GtkActionEntry *entries,
1063 guint n_entries,
1064 gboolean can_show,
1065 gboolean is_online)
1066 {
1067 gint ii;
1068
1069 g_return_if_fail (action_group != NULL);
1070 g_return_if_fail (entries != NULL);
1071
1072 for (ii = 0; ii < n_entries; ii++) {
1073 GtkAction *action;
1074
1075 action = gtk_action_group_get_action (action_group, entries[ii].name);
1076 if (!action)
1077 continue;
1078
1079 gtk_action_set_visible (action, can_show);
1080 if (can_show)
1081 gtk_action_set_sensitive (action, is_online);
1082 }
1083 }
1084
1085 static GtkActionEntry mail_account_context_entries[] = {
1086 { "mail-ews-folder-sizes",
1087 NULL,
1088 N_("Folder Sizes…"),
1089 NULL,
1090 NULL, /* XXX Add a tooltip! */
1091 G_CALLBACK (action_folder_sizes_cb) },
1092
1093 { "mail-ews-subscribe-foreign-folder",
1094 NULL,
1095 N_("Subscribe to folder of other user…"),
1096 NULL,
1097 NULL, /* XXX Add a tooltip! */
1098 G_CALLBACK (action_subscribe_foreign_folder_cb) }
1099 };
1100
1101 static GtkActionEntry mail_folder_context_entries[] = {
1102 { "mail-ews-folder-permissions",
1103 "folder-new",
1104 N_("Permissions…"),
1105 NULL,
1106 N_("Edit EWS folder permissions"),
1107 G_CALLBACK (action_folder_permissions_mail_cb) }
1108 };
1109
1110 static const gchar *ews_ui_mail_def =
1111 "<menubar name='main-menu'>\n"
1112 " <menu action='file-menu'>\n"
1113 " <placeholder name='long-running-actions'>\n"
1114 " <menuitem action=\"ews-global-subscribe-foreign-folder\"/>\n"
1115 " </placeholder>\n"
1116 " </menu>\n"
1117 "</menubar>\n"
1118 "<popup name=\"mail-folder-popup\">\n"
1119 " <placeholder name=\"mail-folder-popup-actions\">\n"
1120 " <menuitem action=\"mail-ews-folder-sizes\"/>\n"
1121 " <menuitem action=\"mail-ews-subscribe-foreign-folder\"/>\n"
1122 " <menuitem action=\"mail-ews-folder-permissions\"/>\n"
1123 " </placeholder>\n"
1124 "</popup>\n";
1125
1126 static void
ews_ui_update_actions_mail_cb(EShellView * shell_view,GtkActionEntry * entries)1127 ews_ui_update_actions_mail_cb (EShellView *shell_view,
1128 GtkActionEntry *entries)
1129 {
1130 EShellWindow *shell_window;
1131 EShellBackend *backend;
1132 CamelSession *session = NULL;
1133 GtkActionGroup *action_group;
1134 GtkUIManager *ui_manager;
1135 EShellSidebar *shell_sidebar;
1136 EMFolderTree *folder_tree;
1137 CamelStore *selected_store = NULL;
1138 gchar *selected_path = NULL;
1139 gboolean account_node = FALSE, folder_node = FALSE;
1140 gboolean online, has_ews_account;
1141
1142 shell_sidebar = e_shell_view_get_shell_sidebar (shell_view);
1143 g_object_get (shell_sidebar, "folder-tree", &folder_tree, NULL);
1144 if (em_folder_tree_get_selected (folder_tree, &selected_store, &selected_path) ||
1145 em_folder_tree_store_root_selected (folder_tree, &selected_store)) {
1146 if (selected_store) {
1147 CamelProvider *provider = camel_service_get_provider (CAMEL_SERVICE (selected_store));
1148
1149 if (provider && g_ascii_strcasecmp (provider->protocol, "ews") == 0) {
1150 account_node = !selected_path || !*selected_path;
1151 folder_node = !account_node;
1152 }
1153
1154 g_object_unref (selected_store);
1155 }
1156 }
1157 g_object_unref (folder_tree);
1158
1159 g_free (selected_path);
1160
1161 shell_window = e_shell_view_get_shell_window (shell_view);
1162 ui_manager = e_shell_window_get_ui_manager (shell_window);
1163 action_group = e_lookup_action_group (ui_manager, "mail");
1164
1165 backend = e_shell_view_get_shell_backend (shell_view);
1166 g_object_get (G_OBJECT (backend), "session", &session, NULL);
1167
1168 online = session && camel_session_get_online (session);
1169
1170 has_ews_account = account_node || folder_node || ews_ui_has_ews_account (shell_view, session);
1171
1172 if (session)
1173 g_object_unref (session);
1174
1175 ews_ui_enable_actions (action_group, mail_account_context_entries, G_N_ELEMENTS (mail_account_context_entries), account_node, online);
1176 ews_ui_enable_actions (action_group, mail_folder_context_entries, G_N_ELEMENTS (mail_folder_context_entries), account_node || folder_node, online);
1177 ews_ui_enable_actions (action_group, global_ews_entries, G_N_ELEMENTS (global_ews_entries), has_ews_account, online);
1178 }
1179
1180 static void
ews_ui_init_mail(GtkUIManager * ui_manager,EShellView * shell_view,gchar ** ui_definition)1181 ews_ui_init_mail (GtkUIManager *ui_manager,
1182 EShellView *shell_view,
1183 gchar **ui_definition)
1184 {
1185 EShellWindow *shell_window;
1186 GtkActionGroup *action_group;
1187
1188 g_return_if_fail (ui_definition != NULL);
1189
1190 *ui_definition = g_strdup (ews_ui_mail_def);
1191
1192 shell_window = e_shell_view_get_shell_window (shell_view);
1193 action_group = e_shell_window_get_action_group (shell_window, "mail");
1194
1195 /* Add actions to the "mail" action group. */
1196 e_action_group_add_actions_localized (
1197 action_group, GETTEXT_PACKAGE,
1198 mail_account_context_entries, G_N_ELEMENTS (mail_account_context_entries), shell_view);
1199 e_action_group_add_actions_localized (
1200 action_group, GETTEXT_PACKAGE,
1201 mail_folder_context_entries, G_N_ELEMENTS (mail_folder_context_entries), shell_view);
1202
1203 /* Add global actions */
1204 e_action_group_add_actions_localized (
1205 action_group, GETTEXT_PACKAGE,
1206 global_ews_entries, G_N_ELEMENTS (global_ews_entries), shell_view);
1207
1208 /* Decide whether we want this option to be visible or not */
1209 g_signal_connect (
1210 shell_view, "update-actions",
1211 G_CALLBACK (ews_ui_update_actions_mail_cb),
1212 shell_view);
1213 }
1214
1215 static gboolean
get_selected_ews_source(EShellView * shell_view,ESource ** selected_source,ESourceRegistry ** registry)1216 get_selected_ews_source (EShellView *shell_view,
1217 ESource **selected_source,
1218 ESourceRegistry **registry)
1219 {
1220 ESource *source;
1221 EShellSidebar *shell_sidebar;
1222 ESourceSelector *selector = NULL;
1223
1224 g_return_val_if_fail (shell_view != NULL, FALSE);
1225
1226 shell_sidebar = e_shell_view_get_shell_sidebar (shell_view);
1227 g_return_val_if_fail (shell_sidebar != NULL, FALSE);
1228
1229 g_object_get (shell_sidebar, "selector", &selector, NULL);
1230 g_return_val_if_fail (selector != NULL, FALSE);
1231
1232 source = e_source_selector_ref_primary_selection (selector);
1233 if (source) {
1234 ESourceBackend *backend_ext = NULL;
1235
1236 if (e_source_has_extension (source, E_SOURCE_EXTENSION_ADDRESS_BOOK))
1237 backend_ext = e_source_get_extension (source, E_SOURCE_EXTENSION_ADDRESS_BOOK);
1238 else if (e_source_has_extension (source, E_SOURCE_EXTENSION_CALENDAR))
1239 backend_ext = e_source_get_extension (source, E_SOURCE_EXTENSION_CALENDAR);
1240 else if (e_source_has_extension (source, E_SOURCE_EXTENSION_MEMO_LIST))
1241 backend_ext = e_source_get_extension (source, E_SOURCE_EXTENSION_MEMO_LIST);
1242 else if (e_source_has_extension (source, E_SOURCE_EXTENSION_TASK_LIST))
1243 backend_ext = e_source_get_extension (source, E_SOURCE_EXTENSION_TASK_LIST);
1244 else if (e_source_has_extension (source, E_SOURCE_EXTENSION_MAIL_ACCOUNT))
1245 backend_ext = e_source_get_extension (source, E_SOURCE_EXTENSION_MAIL_ACCOUNT);
1246
1247 if (!backend_ext ||
1248 g_strcmp0 (e_source_backend_get_backend_name (backend_ext), "ews") != 0) {
1249 g_object_unref (source);
1250 source = NULL;
1251 }
1252 }
1253
1254 if (source && registry)
1255 *registry = g_object_ref (e_source_selector_get_registry (selector));
1256
1257 g_object_unref (selector);
1258
1259 if (selected_source)
1260 *selected_source = source;
1261 else if (source)
1262 g_object_unref (source);
1263
1264 return source != NULL;
1265 }
1266
1267 /* how many menu entries are defined; all calendar/tasks/memos/contacts
1268 * actions should have same count */
1269 #define EWS_ESOURCE_NUM_ENTRIES 1
1270
1271 static void
update_ews_source_entries_cb(EShellView * shell_view,GtkActionEntry * entries)1272 update_ews_source_entries_cb (EShellView *shell_view,
1273 GtkActionEntry *entries)
1274 {
1275 GtkActionGroup *action_group;
1276 EShell *shell;
1277 EShellWindow *shell_window;
1278 ESource *source = NULL;
1279 const gchar *group;
1280 gboolean is_ews_source, is_online;
1281
1282 g_return_if_fail (E_IS_SHELL_VIEW (shell_view));
1283 g_return_if_fail (entries != NULL);
1284
1285 if (strstr (entries->name, "calendar"))
1286 group = "calendar";
1287 else if (strstr (entries->name, "tasks"))
1288 group = "tasks";
1289 else if (strstr (entries->name, "memos"))
1290 group = "memos";
1291 else if (strstr (entries->name, "contacts"))
1292 group = "contacts";
1293 else
1294 g_return_if_reached ();
1295
1296 is_ews_source = get_selected_ews_source (shell_view, &source, NULL);
1297
1298 if (is_ews_source) {
1299 if (!source || !e_source_has_extension (source, E_SOURCE_EXTENSION_EWS_FOLDER))
1300 is_ews_source = FALSE;
1301
1302 if (is_ews_source) {
1303 ESource *clicked_source = NULL;
1304
1305 g_object_get (G_OBJECT (shell_view), "clicked-source", &clicked_source, NULL);
1306
1307 if (clicked_source && clicked_source != source)
1308 is_ews_source = FALSE;
1309
1310 g_clear_object (&clicked_source);
1311 }
1312
1313 if (is_ews_source) {
1314 ESourceEwsFolder *ews_folder = e_source_get_extension (source, E_SOURCE_EXTENSION_EWS_FOLDER);
1315
1316 /* Require both ChangeKey and folder's Id, but GAL can have a ':' in the Id,
1317 which should be ignored, because it's not a valid folder Id. */
1318 if (!e_source_ews_folder_get_id (ews_folder) ||
1319 g_strcmp0 (e_source_ews_folder_get_id (ews_folder), "") == 0 ||
1320 !e_source_ews_folder_get_change_key (ews_folder) ||
1321 g_strcmp0 (e_source_ews_folder_get_change_key (ews_folder), "") == 0 ||
1322 strchr (e_source_ews_folder_get_id (ews_folder), ':') != NULL)
1323 is_ews_source = FALSE;
1324 }
1325 }
1326
1327 g_clear_object (&source);
1328
1329 shell_window = e_shell_view_get_shell_window (shell_view);
1330 shell = e_shell_window_get_shell (shell_window);
1331
1332 is_online = shell && e_shell_get_online (shell);
1333 action_group = e_shell_window_get_action_group (shell_window, group);
1334
1335 ews_ui_enable_actions (action_group, entries, EWS_ESOURCE_NUM_ENTRIES, is_ews_source, is_online);
1336 ews_ui_enable_actions (action_group, global_ews_entries, G_N_ELEMENTS (global_ews_entries),
1337 ews_ui_has_ews_account (shell_view, NULL), is_online);
1338 }
1339
1340 static void
setup_ews_source_actions(EShellView * shell_view,GtkUIManager * ui_manager,GtkActionEntry * entries,guint n_entries)1341 setup_ews_source_actions (EShellView *shell_view,
1342 GtkUIManager *ui_manager,
1343 GtkActionEntry *entries,
1344 guint n_entries)
1345 {
1346 EShellWindow *shell_window;
1347 GtkActionGroup *action_group;
1348 const gchar *group;
1349
1350 g_return_if_fail (shell_view != NULL);
1351 g_return_if_fail (ui_manager != NULL);
1352 g_return_if_fail (entries != NULL);
1353 g_return_if_fail (n_entries > 0);
1354 g_return_if_fail (n_entries == EWS_ESOURCE_NUM_ENTRIES);
1355
1356 if (strstr (entries->name, "calendar"))
1357 group = "calendar";
1358 else if (strstr (entries->name, "tasks"))
1359 group = "tasks";
1360 else if (strstr (entries->name, "memos"))
1361 group = "memos";
1362 else if (strstr (entries->name, "contacts"))
1363 group = "contacts";
1364 else
1365 g_return_if_reached ();
1366
1367 shell_window = e_shell_view_get_shell_window (shell_view);
1368 action_group = e_shell_window_get_action_group (shell_window, group);
1369
1370 e_action_group_add_actions_localized (
1371 action_group, GETTEXT_PACKAGE,
1372 entries, EWS_ESOURCE_NUM_ENTRIES, shell_view);
1373
1374 /* Add global actions */
1375 e_action_group_add_actions_localized (
1376 action_group, GETTEXT_PACKAGE,
1377 global_ews_entries, G_N_ELEMENTS (global_ews_entries), shell_view);
1378
1379 g_signal_connect (shell_view, "update-actions", G_CALLBACK (update_ews_source_entries_cb), entries);
1380 }
1381
1382 static void
action_folder_permissions_source_cb(GtkAction * action,EShellView * shell_view)1383 action_folder_permissions_source_cb (GtkAction *action,
1384 EShellView *shell_view)
1385 {
1386 ESourceRegistry *registry = NULL;
1387 ESource *source = NULL, *parent_source;
1388 ESourceEwsFolder *folder_ext;
1389 ESourceCamel *extension;
1390 CamelSettings *settings;
1391 const gchar *extension_name;
1392 EwsFolderId *folder_id;
1393 EEwsFolderType folder_type;
1394
1395 g_return_if_fail (action != NULL);
1396 g_return_if_fail (shell_view != NULL);
1397 g_return_if_fail (get_selected_ews_source (shell_view, &source, ®istry));
1398 g_return_if_fail (source != NULL);
1399 g_return_if_fail (e_source_has_extension (source, E_SOURCE_EXTENSION_EWS_FOLDER));
1400 g_return_if_fail (gtk_action_get_name (action) != NULL);
1401
1402 folder_ext = e_source_get_extension (source, E_SOURCE_EXTENSION_EWS_FOLDER);
1403 folder_id = e_source_ews_folder_dup_folder_id (folder_ext);
1404 g_return_if_fail (folder_id != NULL);
1405
1406 parent_source = e_source_registry_ref_source (registry, e_source_get_parent (source));
1407
1408 extension_name = e_source_camel_get_extension_name ("ews");
1409 extension = e_source_get_extension (parent_source, extension_name);
1410 settings = e_source_camel_get_settings (extension);
1411
1412 folder_type = E_EWS_FOLDER_TYPE_MAILBOX;
1413 if (strstr (gtk_action_get_name (action), "calendar") != NULL)
1414 folder_type = E_EWS_FOLDER_TYPE_CALENDAR;
1415 else if (strstr (gtk_action_get_name (action), "contacts") != NULL)
1416 folder_type = E_EWS_FOLDER_TYPE_CONTACTS;
1417 else if (strstr (gtk_action_get_name (action), "tasks") != NULL)
1418 folder_type = E_EWS_FOLDER_TYPE_TASKS;
1419
1420 e_ews_edit_folder_permissions (
1421 NULL,
1422 registry,
1423 source,
1424 CAMEL_EWS_SETTINGS (settings),
1425 e_source_get_display_name (parent_source),
1426 e_source_get_display_name (source),
1427 folder_id,
1428 folder_type);
1429
1430 g_object_unref (source);
1431 g_object_unref (parent_source);
1432 g_object_unref (registry);
1433 e_ews_folder_id_free (folder_id);
1434 }
1435
1436 static GtkActionEntry calendar_context_entries[] = {
1437
1438 { "calendar-ews-folder-permissions",
1439 "folder-new",
1440 N_("Permissions…"),
1441 NULL,
1442 N_("Edit EWS calendar permissions"),
1443 G_CALLBACK (action_folder_permissions_source_cb) }
1444 };
1445
1446 static const gchar *ews_ui_cal_def =
1447 "<menubar name='main-menu'>\n"
1448 " <menu action='file-menu'>\n"
1449 " <placeholder name='long-running-actions'>\n"
1450 " <menuitem action=\"ews-global-subscribe-foreign-folder\"/>\n"
1451 " </placeholder>\n"
1452 " </menu>\n"
1453 "</menubar>\n"
1454 "<popup name=\"calendar-popup\">\n"
1455 " <placeholder name=\"calendar-popup-actions\">\n"
1456 " <menuitem action=\"calendar-ews-folder-permissions\"/>\n"
1457 " </placeholder>\n"
1458 "</popup>\n";
1459
1460 static void
ews_ui_init_calendar(GtkUIManager * ui_manager,EShellView * shell_view,gchar ** ui_definition)1461 ews_ui_init_calendar (GtkUIManager *ui_manager,
1462 EShellView *shell_view,
1463 gchar **ui_definition)
1464 {
1465 g_return_if_fail (ui_definition != NULL);
1466
1467 *ui_definition = g_strdup (ews_ui_cal_def);
1468
1469 setup_ews_source_actions (
1470 shell_view, ui_manager,
1471 calendar_context_entries, G_N_ELEMENTS (calendar_context_entries));
1472 }
1473
1474 static GtkActionEntry tasks_context_entries[] = {
1475
1476 { "tasks-ews-folder-permissions",
1477 "folder-new",
1478 N_("Permissions…"),
1479 NULL,
1480 N_("Edit EWS tasks permissions"),
1481 G_CALLBACK (action_folder_permissions_source_cb) }
1482 };
1483
1484 static const gchar *ews_ui_task_def =
1485 "<menubar name='main-menu'>\n"
1486 " <menu action='file-menu'>\n"
1487 " <placeholder name='long-running-actions'>\n"
1488 " <menuitem action=\"ews-global-subscribe-foreign-folder\"/>\n"
1489 " </placeholder>\n"
1490 " </menu>\n"
1491 "</menubar>\n"
1492 "<popup name=\"task-list-popup\">\n"
1493 " <placeholder name=\"task-list-popup-actions\">\n"
1494 " <menuitem action=\"tasks-ews-folder-permissions\"/>\n"
1495 " </placeholder>\n"
1496 "</popup>\n";
1497
1498 static void
ews_ui_init_tasks(GtkUIManager * ui_manager,EShellView * shell_view,gchar ** ui_definition)1499 ews_ui_init_tasks (GtkUIManager *ui_manager,
1500 EShellView *shell_view,
1501 gchar **ui_definition)
1502 {
1503 g_return_if_fail (ui_definition != NULL);
1504
1505 *ui_definition = g_strdup (ews_ui_task_def);
1506
1507 setup_ews_source_actions (
1508 shell_view, ui_manager,
1509 tasks_context_entries, G_N_ELEMENTS (tasks_context_entries));
1510 }
1511
1512 static GtkActionEntry memos_context_entries[] = {
1513
1514 { "memos-ews-folder-permissions",
1515 "folder-new",
1516 N_("Permissions…"),
1517 NULL,
1518 N_("Edit EWS memos permissions"),
1519 G_CALLBACK (action_folder_permissions_source_cb) }
1520 };
1521
1522 static const gchar *ews_ui_memo_def =
1523 "<menubar name='main-menu'>\n"
1524 " <menu action='file-menu'>\n"
1525 " <placeholder name='long-running-actions'>\n"
1526 " <menuitem action=\"ews-global-subscribe-foreign-folder\"/>\n"
1527 " </placeholder>\n"
1528 " </menu>\n"
1529 "</menubar>\n"
1530 "<popup name=\"memo-list-popup\">\n"
1531 " <placeholder name=\"memo-list-popup-actions\">\n"
1532 " <menuitem action=\"memos-ews-folder-permissions\"/>\n"
1533 " </placeholder>\n"
1534 "</popup>\n";
1535
1536 static void
ews_ui_init_memos(GtkUIManager * ui_manager,EShellView * shell_view,gchar ** ui_definition)1537 ews_ui_init_memos (GtkUIManager *ui_manager,
1538 EShellView *shell_view,
1539 gchar **ui_definition)
1540 {
1541 g_return_if_fail (ui_definition != NULL);
1542
1543 *ui_definition = g_strdup (ews_ui_memo_def);
1544
1545 setup_ews_source_actions (
1546 shell_view, ui_manager,
1547 memos_context_entries, G_N_ELEMENTS (memos_context_entries));
1548 }
1549
1550 static GtkActionEntry contacts_context_entries[] = {
1551
1552 { "contacts-ews-folder-permissions",
1553 "folder-new",
1554 N_("Permissions…"),
1555 NULL,
1556 N_("Edit EWS contacts permissions"),
1557 G_CALLBACK (action_folder_permissions_source_cb) }
1558 };
1559
1560 static const gchar *ews_ui_book_def =
1561 "<menubar name='main-menu'>\n"
1562 " <menu action='file-menu'>\n"
1563 " <placeholder name='long-running-actions'>\n"
1564 " <menuitem action=\"ews-global-subscribe-foreign-folder\"/>\n"
1565 " </placeholder>\n"
1566 " </menu>\n"
1567 "</menubar>\n"
1568 "<popup name=\"address-book-popup\">\n"
1569 " <placeholder name=\"address-book-popup-actions\">\n"
1570 " <menuitem action=\"contacts-ews-folder-permissions\"/>\n"
1571 " </placeholder>\n"
1572 "</popup>\n";
1573
1574 static void
ews_ui_init_contacts(GtkUIManager * ui_manager,EShellView * shell_view,gchar ** ui_definition)1575 ews_ui_init_contacts (GtkUIManager *ui_manager,
1576 EShellView *shell_view,
1577 gchar **ui_definition)
1578 {
1579 g_return_if_fail (ui_definition != NULL);
1580
1581 *ui_definition = g_strdup (ews_ui_book_def);
1582
1583 setup_ews_source_actions (
1584 shell_view, ui_manager,
1585 contacts_context_entries, G_N_ELEMENTS (contacts_context_entries));
1586 }
1587
1588 void
e_ews_config_utils_init_ui(EShellView * shell_view,const gchar * ui_manager_id,gchar ** ui_definition)1589 e_ews_config_utils_init_ui (EShellView *shell_view,
1590 const gchar *ui_manager_id,
1591 gchar **ui_definition)
1592 {
1593 EShellWindow *shell_window;
1594 GtkUIManager *ui_manager;
1595
1596 g_return_if_fail (shell_view != NULL);
1597 g_return_if_fail (ui_manager_id != NULL);
1598 g_return_if_fail (ui_definition != NULL);
1599
1600 shell_window = e_shell_view_get_shell_window (shell_view);
1601 ui_manager = e_shell_window_get_ui_manager (shell_window);
1602
1603 if (g_strcmp0 (ui_manager_id, "org.gnome.evolution.mail") == 0)
1604 ews_ui_init_mail (ui_manager, shell_view, ui_definition);
1605 else if (g_strcmp0 (ui_manager_id, "org.gnome.evolution.calendars") == 0)
1606 ews_ui_init_calendar (ui_manager, shell_view, ui_definition);
1607 else if (g_strcmp0 (ui_manager_id, "org.gnome.evolution.tasks") == 0)
1608 ews_ui_init_tasks (ui_manager, shell_view, ui_definition);
1609 else if (g_strcmp0 (ui_manager_id, "org.gnome.evolution.memos") == 0)
1610 ews_ui_init_memos (ui_manager, shell_view, ui_definition);
1611 else if (g_strcmp0 (ui_manager_id, "org.gnome.evolution.contacts") == 0)
1612 ews_ui_init_contacts (ui_manager, shell_view, ui_definition);
1613 }
1614
1615 gboolean
e_ews_config_utils_is_online(void)1616 e_ews_config_utils_is_online (void)
1617 {
1618 EShell *shell;
1619
1620 shell = e_shell_get_default ();
1621
1622 return shell && e_shell_get_online (shell);
1623 }
1624
1625 GtkWindow *
e_ews_config_utils_get_widget_toplevel_window(GtkWidget * widget)1626 e_ews_config_utils_get_widget_toplevel_window (GtkWidget *widget)
1627 {
1628 if (!widget)
1629 return NULL;
1630
1631 if (!GTK_IS_WINDOW (widget))
1632 widget = gtk_widget_get_toplevel (widget);
1633
1634 if (GTK_IS_WINDOW (widget))
1635 return GTK_WINDOW (widget);
1636
1637 return NULL;
1638 }
1639
1640 static gpointer
ews_config_utils_unref_in_thread(gpointer user_data)1641 ews_config_utils_unref_in_thread (gpointer user_data)
1642 {
1643 g_object_unref (user_data);
1644
1645 return NULL;
1646 }
1647
1648 void
e_ews_config_utils_unref_in_thread(GObject * object)1649 e_ews_config_utils_unref_in_thread (GObject *object)
1650 {
1651 GThread *thread;
1652
1653 g_return_if_fail (object != NULL);
1654 g_return_if_fail (G_IS_OBJECT (object));
1655
1656 thread = g_thread_new (NULL, ews_config_utils_unref_in_thread, object);
1657 g_thread_unref (thread);
1658 }
1659