"Fossies" - the Fresh Open Source Software Archive

Member "evolution-mapi-3.46.1/src/configuration/e-mapi-config-utils.c" (2 Dec 2022, 56569 Bytes) of package /linux/misc/evolution-mapi-3.46.1.tar.xz:


As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) C and C++ source code syntax highlighting (style: standard) with prefixed line numbers and code folding option. Alternatively you can here view or download the uninterpreted source code file. For more information about "e-mapi-config-utils.c" see the Fossies "Dox" file reference documentation and the last Fossies "Diffs" side-by-side code changes report: 3.44.0_vs_3.44.1.

    1 /*
    2  * e-mapi-config-utils.c
    3  *
    4  * This program is free software; you can redistribute it and/or
    5  * modify it under the terms of the GNU Lesser General Public
    6  * License as published by the Free Software Foundation; either
    7  * version 2 of the License, or (at your option) version 3.
    8  *
    9  * This program is distributed in the hope that it will be useful,
   10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
   11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
   12  * Lesser General Public License for more details.
   13  *
   14  * You should have received a copy of the GNU Lesser General Public
   15  * License along with the program; if not, see <http://www.gnu.org/licenses/>
   16  *
   17  */
   18 
   19 #include "evolution-mapi-config.h"
   20 
   21 #include <string.h>
   22 #include <unistd.h>
   23 #include <glib/gi18n-lib.h>
   24 
   25 #include <gtk/gtk.h>
   26 #include <libedataserver/libedataserver.h>
   27 #include <libedataserverui/libedataserverui.h>
   28 
   29 #include <e-util/e-util.h>
   30 
   31 #include <mail/em-folder-tree.h>
   32 #include <shell/e-shell.h>
   33 #include <shell/e-shell-sidebar.h>
   34 #include <shell/e-shell-view.h>
   35 #include <shell/e-shell-window.h>
   36 
   37 #include "e-mapi-folder.h"
   38 #include "e-mapi-connection.h"
   39 #include "e-mapi-utils.h"
   40 #include "e-source-mapi-folder.h"
   41 
   42 #include "e-mapi-subscribe-foreign-folder.h"
   43 #include "e-mapi-edit-folder-permissions.h"
   44 
   45 #include "camel/camel-mapi-store.h"
   46 #include "camel/camel-mapi-store-summary.h"
   47 
   48 #include "e-mapi-config-utils.h"
   49 
   50 struct RunWithFeedbackData
   51 {
   52     GtkWindow *parent;
   53     GtkWidget *dialog;
   54     GCancellable *cancellable;
   55     GObject *with_object;
   56     EMapiSetupFunc thread_func;
   57     EMapiSetupFunc idle_func;
   58     gpointer user_data;
   59     GDestroyNotify free_user_data;
   60     GError *error;
   61     gboolean run_modal;
   62 };
   63 
   64 static void
   65 free_run_with_feedback_data (gpointer ptr)
   66 {
   67     struct RunWithFeedbackData *rfd = ptr;
   68 
   69     if (!rfd)
   70         return;
   71 
   72     if (rfd->dialog)
   73         gtk_widget_destroy (rfd->dialog);
   74 
   75     g_object_unref (rfd->cancellable);
   76     g_object_unref (rfd->with_object);
   77 
   78     if (rfd->free_user_data)
   79         rfd->free_user_data (rfd->user_data);
   80 
   81     g_clear_error (&rfd->error);
   82 
   83     g_slice_free (struct RunWithFeedbackData, rfd);
   84 }
   85 
   86 static gboolean
   87 run_with_feedback_idle (gpointer user_data)
   88 {
   89     struct RunWithFeedbackData *rfd = user_data;
   90     gboolean was_cancelled = FALSE;
   91 
   92     g_return_val_if_fail (rfd != NULL, FALSE);
   93 
   94     if (!g_cancellable_is_cancelled (rfd->cancellable)) {
   95         if (rfd->idle_func && !rfd->error)
   96             rfd->idle_func (rfd->with_object, rfd->user_data, rfd->cancellable, &rfd->error);
   97 
   98         was_cancelled = g_cancellable_is_cancelled (rfd->cancellable);
   99 
  100         if (rfd->dialog) {
  101             gtk_widget_destroy (rfd->dialog);
  102             rfd->dialog = NULL;
  103         }
  104     } else {
  105         was_cancelled = TRUE;
  106     }
  107 
  108     if (!was_cancelled) {
  109         if (rfd->error)
  110             e_notice (rfd->parent, GTK_MESSAGE_ERROR, "%s", rfd->error->message);
  111     }
  112 
  113     free_run_with_feedback_data (rfd);
  114 
  115     return FALSE;
  116 }
  117 
  118 static gpointer
  119 run_with_feedback_thread (gpointer user_data)
  120 {
  121     struct RunWithFeedbackData *rfd = user_data;
  122 
  123     g_return_val_if_fail (rfd != NULL, NULL);
  124     g_return_val_if_fail (rfd->thread_func != NULL, NULL);
  125 
  126     if (!g_cancellable_is_cancelled (rfd->cancellable))
  127         rfd->thread_func (rfd->with_object, rfd->user_data, rfd->cancellable, &rfd->error);
  128 
  129     g_idle_add (run_with_feedback_idle, rfd);
  130 
  131     return NULL;
  132 }
  133 
  134 static void
  135 run_with_feedback_response_cb (GtkWidget *dialog,
  136                    gint resonse_id,
  137                    struct RunWithFeedbackData *rfd)
  138 {
  139     g_return_if_fail (rfd != NULL);
  140 
  141     rfd->dialog = NULL;
  142 
  143     g_cancellable_cancel (rfd->cancellable);
  144 
  145     gtk_widget_destroy (dialog);
  146 }
  147 
  148 static void
  149 e_mapi_config_utils_run_in_thread_with_feedback_general (GtkWindow *parent,
  150                         GObject *with_object,
  151                         const gchar *description,
  152                         EMapiSetupFunc thread_func,
  153                         EMapiSetupFunc idle_func,
  154                         gpointer user_data,
  155                         GDestroyNotify free_user_data,
  156                         gboolean run_modal)
  157 {
  158     GtkWidget *dialog, *label, *content, *spinner, *box;
  159     struct RunWithFeedbackData *rfd;
  160 
  161     g_return_if_fail (with_object != NULL);
  162     g_return_if_fail (description != NULL);
  163     g_return_if_fail (thread_func != NULL);
  164 
  165     dialog = gtk_dialog_new_with_buttons ("",
  166         parent,
  167         GTK_DIALOG_MODAL,
  168         GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL,
  169         NULL);
  170 
  171     box = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 6);
  172 
  173     spinner = e_spinner_new ();
  174     e_spinner_start (E_SPINNER (spinner));
  175     gtk_box_pack_start (GTK_BOX (box), spinner, FALSE, FALSE, 0);
  176 
  177     label = gtk_label_new (description);
  178     gtk_box_pack_start (GTK_BOX (box), label, TRUE, TRUE, 0);
  179 
  180     gtk_widget_show_all (box);
  181 
  182     content = gtk_dialog_get_content_area (GTK_DIALOG (dialog));
  183 
  184     gtk_container_add (GTK_CONTAINER (content), box);
  185     gtk_container_set_border_width (GTK_CONTAINER (content), 12);
  186 
  187     rfd = g_slice_new0 (struct RunWithFeedbackData);
  188     rfd->parent = parent;
  189     rfd->dialog = dialog;
  190     rfd->cancellable = g_cancellable_new ();
  191     rfd->with_object = g_object_ref (with_object);
  192     rfd->thread_func = thread_func;
  193     rfd->idle_func = idle_func;
  194     rfd->user_data = user_data;
  195     rfd->free_user_data = free_user_data;
  196     rfd->error = NULL;
  197     rfd->run_modal = run_modal;
  198 
  199     g_signal_connect (dialog, "response", G_CALLBACK (run_with_feedback_response_cb), rfd);
  200 
  201     if (run_modal) {
  202         GThread *thread;
  203         GCancellable *cancellable;
  204 
  205         cancellable = g_object_ref (rfd->cancellable);
  206 
  207         thread = g_thread_new (NULL, run_with_feedback_thread, rfd);
  208         g_thread_unref (thread);
  209 
  210         gtk_dialog_run (GTK_DIALOG (dialog));
  211 
  212         g_cancellable_cancel (cancellable);
  213         g_object_unref (cancellable);
  214     } else {
  215         GThread *thread;
  216 
  217         gtk_widget_show (dialog);
  218 
  219         thread = g_thread_new (NULL, run_with_feedback_thread, rfd);
  220         g_thread_unref (thread);
  221     }
  222 }
  223 
  224 void
  225 e_mapi_config_utils_run_in_thread_with_feedback (GtkWindow *parent,
  226                     GObject *with_object,
  227                     const gchar *description,
  228                     EMapiSetupFunc thread_func,
  229                     EMapiSetupFunc idle_func,
  230                     gpointer user_data,
  231                     GDestroyNotify free_user_data)
  232 {
  233     e_mapi_config_utils_run_in_thread_with_feedback_general (parent, with_object, description, thread_func, idle_func, user_data, free_user_data, FALSE);
  234 }
  235 
  236 void
  237 e_mapi_config_utils_run_in_thread_with_feedback_modal (GtkWindow *parent,
  238                       GObject *with_object,
  239                       const gchar *description,
  240                       EMapiSetupFunc thread_func,
  241                       EMapiSetupFunc idle_func,
  242                       gpointer user_data,
  243                       GDestroyNotify free_user_data)
  244 {
  245     e_mapi_config_utils_run_in_thread_with_feedback_general (parent, with_object, description, thread_func, idle_func, user_data, free_user_data, TRUE);
  246 }
  247 
  248 typedef struct _TryCredentialsData {
  249     ESourceRegistry *registry;
  250     CamelMapiSettings *mapi_settings;
  251     EMapiConnection *conn;
  252 } TryCredentialsData;
  253 
  254 static gboolean
  255 mapi_config_utils_try_credentials_sync (ECredentialsPrompter *prompter,
  256                     ESource *source,
  257                     const ENamedParameters *credentials,
  258                     gboolean *out_authenticated,
  259                     gpointer user_data,
  260                     GCancellable *cancellable,
  261                     GError **error)
  262 {
  263     TryCredentialsData *data = user_data;
  264     EMapiProfileData empd = { 0 };
  265     CamelNetworkSettings *network_settings;
  266     GError *mapi_error = NULL;
  267 
  268     network_settings = CAMEL_NETWORK_SETTINGS (data->mapi_settings);
  269 
  270     empd.server = camel_network_settings_get_host (network_settings);
  271     empd.username = camel_network_settings_get_user (network_settings);
  272     e_mapi_util_profiledata_from_settings (&empd, data->mapi_settings);
  273 
  274     data->conn = e_mapi_connection_new (
  275         data->registry,
  276         camel_mapi_settings_get_profile (data->mapi_settings),
  277         credentials, cancellable, &mapi_error);
  278 
  279     if (mapi_error) {
  280         g_warn_if_fail (!data->conn);
  281         data->conn = NULL;
  282 
  283         g_propagate_error (error, mapi_error);
  284 
  285         return FALSE;
  286     }
  287 
  288     g_warn_if_fail (data->conn);
  289     *out_authenticated = TRUE;
  290 
  291     return TRUE;
  292 }
  293 
  294 EMapiConnection *
  295 e_mapi_config_utils_open_connection_for (GtkWindow *parent,
  296                      ESourceRegistry *registry,
  297                      ESource *source,
  298                      CamelMapiSettings *mapi_settings,
  299                      GCancellable *cancellable,
  300                      GError **perror)
  301 {
  302     const gchar *profile;
  303     EMapiConnection *conn = NULL;
  304     EMapiProfileData empd = { 0 };
  305     CamelNetworkSettings *network_settings;
  306     GError *local_error = NULL;
  307 
  308     g_return_val_if_fail (registry != NULL, NULL);
  309     g_return_val_if_fail (source != NULL, NULL);
  310     g_return_val_if_fail (mapi_settings != NULL, NULL);
  311 
  312     profile = camel_mapi_settings_get_profile (mapi_settings);
  313 
  314     /* use the one from mailer, if there, otherwise open new */
  315     conn = e_mapi_connection_find (profile);
  316     if (conn)
  317         return conn;
  318 
  319     network_settings = CAMEL_NETWORK_SETTINGS (mapi_settings);
  320 
  321     empd.server = camel_network_settings_get_host (network_settings);
  322     empd.username = camel_network_settings_get_user (network_settings);
  323     e_mapi_util_profiledata_from_settings (&empd, mapi_settings);
  324 
  325     if (empd.krb_sso)
  326         conn = e_mapi_connection_new (registry, profile, NULL, cancellable, &local_error);
  327 
  328     while (!conn && !g_cancellable_is_cancelled (cancellable) && !local_error) {
  329         if (empd.krb_sso) {
  330             GError *krb_error = NULL;
  331 
  332             e_mapi_util_trigger_krb_auth (&empd, &krb_error);
  333 
  334             conn = e_mapi_connection_new (registry, profile, NULL, cancellable, &local_error);
  335 
  336             if (!conn && krb_error) {
  337                 if (local_error) {
  338                     GError *new_error = g_error_new (local_error->domain, local_error->code,
  339                         /* Translators: the first '%s' is replaced with a generic error message,
  340                            the second '%s' is replaced with additional error information. */
  341                         C_("gssapi_error", "%s (%s)"), local_error->message, krb_error->message);
  342                     g_clear_error (&local_error);
  343                     local_error = new_error;
  344                 } else {
  345                     local_error = krb_error;
  346                     krb_error = NULL;
  347                 }
  348             }
  349 
  350             g_clear_error (&krb_error);
  351         } else {
  352             EShell *shell;
  353             TryCredentialsData data;
  354 
  355             shell = e_shell_get_default ();
  356 
  357             data.mapi_settings = g_object_ref (mapi_settings);
  358             data.registry = g_object_ref (registry);
  359             data.conn = NULL;
  360 
  361             e_credentials_prompter_loop_prompt_sync (e_shell_get_credentials_prompter (shell),
  362                 source, E_CREDENTIALS_PROMPTER_PROMPT_FLAG_ALLOW_SOURCE_SAVE,
  363                 mapi_config_utils_try_credentials_sync, &data, cancellable, &local_error);
  364 
  365             if (data.conn)
  366                 conn = g_object_ref (data.conn);
  367 
  368             g_clear_object (&data.mapi_settings);
  369             g_clear_object (&data.registry);
  370             g_clear_object (&data.conn);
  371         }
  372     }
  373 
  374     if (local_error)
  375         g_propagate_error (perror, local_error);
  376 
  377     return conn;
  378 }
  379 
  380 #define FOLDERSIZE_MENU_ITEM 0
  381 
  382 enum {
  383     COL_FOLDERSIZE_NAME = 0,
  384     COL_FOLDERSIZE_SIZE,
  385     COL_FOLDERSIZE_MAX
  386 };
  387 
  388 typedef struct
  389 {
  390     GtkDialog *dialog;
  391     GtkGrid *spinner_grid;
  392 
  393     ESourceRegistry *registry;
  394     ESource *source;
  395     CamelMapiSettings *mapi_settings;
  396 
  397     GSList *folder_list;
  398     GCancellable *cancellable;
  399     GError *error;
  400 } FolderSizeDialogData;
  401 
  402 static gboolean
  403 mapi_settings_get_folder_size_idle (gpointer user_data)
  404 {
  405     GtkWidget *widget;
  406     GtkCellRenderer *renderer;
  407     GtkListStore *store;
  408     GtkTreeIter iter;
  409     GtkBox *content_area;
  410     FolderSizeDialogData *fsd = user_data;
  411 
  412     g_return_val_if_fail (fsd != NULL, FALSE);
  413 
  414     if (g_cancellable_is_cancelled (fsd->cancellable))
  415         goto cleanup;
  416 
  417     /* Hide progress bar. Set status*/
  418     gtk_widget_destroy (GTK_WIDGET (fsd->spinner_grid));
  419 
  420     if (fsd->folder_list) {
  421         GtkWidget *scrolledwindow, *tree_view;
  422         GSList *fiter;
  423 
  424         scrolledwindow = gtk_scrolled_window_new (NULL, NULL);
  425         gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (scrolledwindow), GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC);
  426         gtk_widget_show (scrolledwindow);
  427 
  428         /*Tree View */
  429         tree_view =  gtk_tree_view_new ();
  430         renderer = gtk_cell_renderer_text_new ();
  431         gtk_tree_view_insert_column_with_attributes (GTK_TREE_VIEW (tree_view),-1,
  432                                  _("Folder"), renderer, "text", COL_FOLDERSIZE_NAME,
  433                                  NULL);
  434 
  435         renderer = gtk_cell_renderer_text_new ();
  436         gtk_tree_view_insert_column_with_attributes (GTK_TREE_VIEW (tree_view),-1,
  437                                  _("Size"), renderer, "text", COL_FOLDERSIZE_SIZE,
  438                                  NULL);
  439         /* Model for TreeView */
  440         store = gtk_list_store_new (2, G_TYPE_STRING, G_TYPE_STRING);
  441         gtk_tree_view_set_model (GTK_TREE_VIEW (tree_view), GTK_TREE_MODEL (store));
  442 
  443         /* Populate model with data */
  444         for (fiter = fsd->folder_list; fiter;  fiter = fiter->next) {
  445             EMapiFolder *folder = fiter->data;
  446             gchar *folder_size = g_format_size_full (folder->size, G_FORMAT_SIZE_IEC_UNITS);
  447 
  448             gtk_list_store_append (store, &iter);
  449             gtk_list_store_set (store, &iter,
  450                         COL_FOLDERSIZE_NAME, folder->folder_name,
  451                         COL_FOLDERSIZE_SIZE, folder_size,
  452                         -1);
  453 
  454             g_free (folder_size);
  455         }
  456 
  457         gtk_container_add (GTK_CONTAINER (scrolledwindow), tree_view);
  458         widget = scrolledwindow;
  459     } else if (fsd->error) {
  460         gchar *msg = g_strconcat (_("Unable to retrieve folder size information"), "\n", fsd->error->message, NULL);
  461         widget = gtk_label_new (msg);
  462         g_free (msg);
  463     } else {
  464         widget = gtk_label_new (_("Unable to retrieve folder size information"));
  465     }
  466 
  467     gtk_widget_show_all (widget);
  468 
  469     /* Pack into content_area */
  470     content_area = GTK_BOX (gtk_dialog_get_content_area (fsd->dialog));
  471     gtk_box_pack_start (content_area, widget, TRUE, TRUE, 6);
  472 
  473  cleanup:
  474     e_mapi_folder_free_list (fsd->folder_list);
  475     g_object_unref (fsd->registry);
  476     g_object_unref (fsd->source);
  477     g_object_unref (fsd->mapi_settings);
  478     g_object_unref (fsd->cancellable);
  479     g_clear_error (&fsd->error);
  480     g_slice_free (FolderSizeDialogData, fsd);
  481 
  482     return FALSE;
  483 }
  484 
  485 static gpointer
  486 mapi_settings_get_folder_size_thread (gpointer user_data)
  487 {
  488     FolderSizeDialogData *fsd = user_data;
  489     EMapiConnection *conn;
  490 
  491     g_return_val_if_fail (fsd != NULL, NULL);
  492 
  493     fsd->folder_list = NULL;
  494     conn = e_mapi_config_utils_open_connection_for (GTK_WINDOW (fsd->dialog),
  495         fsd->registry,
  496         fsd->source,
  497         fsd->mapi_settings,
  498         fsd->cancellable,
  499         &fsd->error);
  500 
  501     if (conn && e_mapi_connection_connected (conn)) {
  502         fsd->folder_list = NULL;
  503         e_mapi_connection_get_folders_list (conn,
  504             &fsd->folder_list,
  505             NULL, NULL,
  506             fsd->cancellable, &fsd->error);
  507     }
  508 
  509     if (conn)
  510         g_object_unref (conn);
  511 
  512     g_idle_add (mapi_settings_get_folder_size_idle, fsd);
  513 
  514     return NULL;
  515 }
  516 
  517 void
  518 e_mapi_config_utils_run_folder_size_dialog (ESourceRegistry *registry,
  519                         ESource *source,
  520                         CamelMapiSettings *mapi_settings)
  521 {
  522     GtkBox *content_area;
  523     GtkWidget *spinner, *alignment, *dialog;
  524     GtkWidget *spinner_label;
  525     GCancellable *cancellable;
  526     GThread *thread;
  527     FolderSizeDialogData *fsd;
  528 
  529     g_return_if_fail (mapi_settings != NULL);
  530 
  531     dialog = gtk_dialog_new_with_buttons (_("Folder Size"), NULL,
  532         GTK_DIALOG_DESTROY_WITH_PARENT,
  533         GTK_STOCK_CLOSE, GTK_RESPONSE_ACCEPT,
  534         NULL);
  535 
  536     fsd = g_slice_new0 (FolderSizeDialogData);
  537     fsd->dialog = GTK_DIALOG (dialog);
  538 
  539     gtk_window_set_default_size (GTK_WINDOW (fsd->dialog), 250, 300);
  540 
  541     content_area = GTK_BOX (gtk_dialog_get_content_area (fsd->dialog));
  542 
  543     spinner = e_spinner_new ();
  544     e_spinner_start (E_SPINNER (spinner));
  545     spinner_label = gtk_label_new (_("Fetching folder list…"));
  546 
  547     fsd->spinner_grid = GTK_GRID (gtk_grid_new ());
  548     gtk_grid_set_column_spacing (fsd->spinner_grid, 6);
  549     gtk_grid_set_column_homogeneous (fsd->spinner_grid, FALSE);
  550     gtk_orientable_set_orientation (GTK_ORIENTABLE (fsd->spinner_grid), GTK_ORIENTATION_HORIZONTAL);
  551 
  552     alignment = gtk_alignment_new (1.0, 0.5, 0.0, 1.0);
  553     gtk_container_add (GTK_CONTAINER (alignment), spinner);
  554     gtk_misc_set_alignment (GTK_MISC (spinner_label), 0.0, 0.5);
  555 
  556     gtk_container_add (GTK_CONTAINER (fsd->spinner_grid), alignment);
  557     gtk_container_add (GTK_CONTAINER (fsd->spinner_grid), spinner_label);
  558 
  559     /* Pack the TreeView into dialog's content area */
  560     gtk_box_pack_start (content_area, GTK_WIDGET (fsd->spinner_grid), TRUE, TRUE, 6);
  561     gtk_widget_show_all (GTK_WIDGET (fsd->dialog));
  562 
  563     cancellable = g_cancellable_new ();
  564     fsd->registry = g_object_ref (registry);
  565     fsd->source = g_object_ref (source);
  566     fsd->mapi_settings = g_object_ref (mapi_settings);
  567     fsd->cancellable = g_object_ref (cancellable);
  568 
  569     thread = g_thread_new (NULL, mapi_settings_get_folder_size_thread, fsd);
  570     g_thread_unref (thread);
  571 
  572     /* Start the dialog */
  573     gtk_dialog_run (GTK_DIALOG (dialog));
  574 
  575     g_cancellable_cancel (cancellable);
  576     g_object_unref (cancellable);
  577     gtk_widget_destroy (GTK_WIDGET (dialog));
  578 }
  579 
  580 static void
  581 action_global_subscribe_foreign_folder_cb (GtkAction *action,
  582                        EShellView *shell_view)
  583 {
  584     EShell *shell;
  585     EShellBackend *shell_backend;
  586     EShellWindow *shell_window;
  587     EClientCache *client_cache;
  588     CamelSession *session = NULL;
  589 
  590     g_return_if_fail (E_IS_SHELL_VIEW (shell_view));
  591 
  592     shell_window = e_shell_view_get_shell_window (shell_view);
  593     shell = e_shell_window_get_shell (shell_window);
  594     shell_backend = e_shell_get_backend_by_name (shell, "mail");
  595 
  596     if (shell_backend)
  597         g_object_get (G_OBJECT (shell_backend), "session", &session, NULL);
  598 
  599     if (!session)
  600         return;
  601 
  602     client_cache = e_shell_get_client_cache (shell);
  603 
  604     e_mapi_subscribe_foreign_folder (GTK_WINDOW (shell_window), session, NULL, client_cache);
  605 
  606     g_object_unref (session);
  607 }
  608 
  609 static GtkActionEntry global_mapi_entries[] = {
  610     { "mapi-global-subscribe-foreign-folder",
  611       NULL,
  612       N_("Subscribe to folder of other MAPI user…"),
  613       NULL,
  614       NULL,  /* XXX Add a tooltip! */
  615       G_CALLBACK (action_global_subscribe_foreign_folder_cb) }
  616 };
  617 
  618 static gboolean
  619 mapi_ui_has_mapi_account (EShellView *shell_view,
  620               CamelSession *in_session)
  621 {
  622     CamelSession *session = in_session;
  623     EShell *shell;
  624     gboolean has_any = FALSE;
  625 
  626     g_return_val_if_fail (E_IS_SHELL_VIEW (shell_view), FALSE);
  627     if (in_session)
  628         g_return_val_if_fail (CAMEL_IS_SESSION (in_session), FALSE);
  629 
  630     shell = e_shell_window_get_shell (e_shell_view_get_shell_window (shell_view));
  631 
  632     if (!session) {
  633         EShellBackend *shell_backend;
  634 
  635         shell_backend = e_shell_get_backend_by_name (shell, "mail");
  636 
  637         if (shell_backend) {
  638             g_object_get (G_OBJECT (shell_backend), "session", &session, NULL);
  639         }
  640     }
  641 
  642     if (session) {
  643         ESourceRegistry *registry;
  644         GList *services, *link;
  645 
  646         registry = e_shell_get_registry (shell);
  647         services = camel_session_list_services (session);
  648 
  649         for (link = services; link && !has_any; link = g_list_next (link)) {
  650             CamelService *service = link->data;
  651 
  652             if (CAMEL_IS_MAPI_STORE (service)) {
  653                 ESource *source;
  654 
  655                 source = e_source_registry_ref_source (registry, camel_service_get_uid (service));
  656                 has_any = source && e_source_registry_check_enabled (registry, source);
  657 
  658                 g_clear_object (&source);
  659             }
  660         }
  661 
  662         g_list_free_full (services, g_object_unref);
  663     }
  664 
  665     if (session && session != in_session)
  666         g_object_unref (session);
  667 
  668     return has_any;
  669 }
  670 
  671 static gchar *
  672 get_profile_name_from_folder_tree (EShellView *shell_view,
  673                    gchar **pfolder_path,
  674                    CamelStore **pstore)
  675 {
  676     EShellSidebar *shell_sidebar;
  677     EMFolderTree *folder_tree;
  678     gchar *profile = NULL, *selected_path = NULL;
  679     CamelStore *selected_store = NULL;
  680 
  681     /* Get hold of Folder Tree */
  682     shell_sidebar = e_shell_view_get_shell_sidebar (shell_view);
  683     g_object_get (shell_sidebar, "folder-tree", &folder_tree, NULL);
  684     if (em_folder_tree_get_selected (folder_tree, &selected_store, &selected_path) ||
  685         em_folder_tree_store_root_selected (folder_tree, &selected_store)) {
  686         if (selected_store) {
  687             CamelProvider *provider = camel_service_get_provider (CAMEL_SERVICE (selected_store));
  688 
  689             if (provider && g_ascii_strcasecmp (provider->protocol, "mapi") == 0) {
  690                 CamelService *service;
  691                 CamelSettings *settings;
  692 
  693                 service = CAMEL_SERVICE (selected_store);
  694 
  695                 settings = camel_service_ref_settings (service);
  696                 g_object_get (settings, "profile", &profile, NULL);
  697                 g_object_unref (settings);
  698 
  699                 if (pstore && profile)
  700                     *pstore = g_object_ref (selected_store);
  701 
  702                 if (pfolder_path)
  703                     *pfolder_path = selected_path;
  704                 else
  705                     g_free (selected_path);
  706 
  707                 selected_path = NULL;
  708             }
  709 
  710             g_object_unref (selected_store);
  711         }
  712 
  713         g_free (selected_path);
  714     }
  715 
  716     g_object_unref (folder_tree);
  717 
  718     return profile;
  719 }
  720 
  721 static void
  722 action_folder_size_cb (GtkAction *action,
  723                EShellView *shell_view)
  724 {
  725     gchar *profile;
  726     CamelSession *session;
  727     CamelStore *store = NULL;
  728 
  729     profile = get_profile_name_from_folder_tree (shell_view, NULL, &store);
  730     if (profile && store) {
  731         CamelSettings *settings;
  732         ESourceRegistry *registry;
  733         ESource *source;
  734 
  735         session = camel_service_ref_session (CAMEL_SERVICE (store));
  736         registry = e_mail_session_get_registry (E_MAIL_SESSION (session));
  737         source = e_source_registry_ref_source (registry, camel_service_get_uid (CAMEL_SERVICE (store)));
  738 
  739         settings = camel_service_ref_settings (CAMEL_SERVICE (store));
  740 
  741         e_mapi_config_utils_run_folder_size_dialog (
  742             registry, source, CAMEL_MAPI_SETTINGS (settings));
  743 
  744         g_object_unref (settings);
  745 
  746         g_object_unref (source); 
  747 
  748         g_object_unref (session);
  749     }
  750 
  751     g_free (profile);
  752     if (store)
  753         g_object_unref (store);
  754 }
  755 
  756 static void
  757 action_subscribe_foreign_folder_cb (GtkAction *action,
  758                     EShellView *shell_view)
  759 {
  760     gchar *profile;
  761     GtkWindow *parent;
  762     EShell *shell;
  763     EShellBackend *backend;
  764     EClientCache *client_cache;
  765     CamelSession *session = NULL;
  766     CamelStore *store = NULL;
  767 
  768     profile = get_profile_name_from_folder_tree (shell_view, NULL, &store);
  769     if (!profile)
  770         return;
  771 
  772     parent = GTK_WINDOW (e_shell_view_get_shell_window (shell_view));
  773     backend = e_shell_view_get_shell_backend (shell_view);
  774     g_object_get (G_OBJECT (backend), "session", &session, NULL);
  775 
  776     shell = e_shell_backend_get_shell (backend);
  777     client_cache = e_shell_get_client_cache (shell);
  778 
  779     e_mapi_subscribe_foreign_folder (parent, session, store, client_cache);
  780 
  781     g_object_unref (session);
  782     g_object_unref (store);
  783     g_free (profile);
  784 }
  785 
  786 static void
  787 action_folder_permissions_mail_cb (GtkAction *action,
  788                    EShellView *shell_view)
  789 {
  790     gchar *profile, *folder_path = NULL;
  791     EShellWindow *shell_window;
  792     GtkWindow *parent;
  793     CamelStore *store = NULL;
  794     CamelMapiStore *mapi_store;
  795     CamelStoreInfo *si;
  796 
  797     profile = get_profile_name_from_folder_tree (shell_view, &folder_path, &store);
  798     if (!profile)
  799         return;
  800 
  801     mapi_store = CAMEL_MAPI_STORE (store);
  802     g_return_if_fail (mapi_store != NULL);
  803     g_return_if_fail (folder_path != NULL);
  804 
  805     shell_window = e_shell_view_get_shell_window (shell_view);
  806     parent = GTK_WINDOW (shell_window);
  807 
  808     si = camel_store_summary_path (mapi_store->summary, folder_path);
  809     if (!si) {
  810         e_notice (parent, GTK_MESSAGE_ERROR, _("Cannot edit permissions of folder “%s”, choose other folder."), folder_path);
  811     } else {
  812         CamelMapiStoreInfo *msi = (CamelMapiStoreInfo *) si;
  813         ESourceRegistry *registry = e_shell_get_registry (e_shell_window_get_shell (shell_window));
  814         ESource *source;
  815         CamelSettings *settings;
  816 
  817         source = e_source_registry_ref_source (registry, camel_service_get_uid (CAMEL_SERVICE (store)));
  818         g_return_if_fail (source != NULL);
  819 
  820         settings = camel_service_ref_settings (CAMEL_SERVICE (store));
  821 
  822         e_mapi_edit_folder_permissions (parent,
  823             registry,
  824             source,
  825             CAMEL_MAPI_SETTINGS (settings),
  826             camel_service_get_display_name (CAMEL_SERVICE (store)),
  827             folder_path,
  828             msi->folder_id,
  829             (msi->mapi_folder_flags & CAMEL_MAPI_STORE_FOLDER_FLAG_FOREIGN) != 0 ? E_MAPI_FOLDER_CATEGORY_FOREIGN :
  830             (msi->mapi_folder_flags & CAMEL_MAPI_STORE_FOLDER_FLAG_PUBLIC) != 0 ? E_MAPI_FOLDER_CATEGORY_PUBLIC :
  831             E_MAPI_FOLDER_CATEGORY_PERSONAL,
  832             msi->foreign_username,
  833             FALSE);
  834 
  835         g_object_unref (settings);
  836 
  837         g_object_unref (source);
  838     }
  839 
  840     g_object_unref (store);
  841     g_free (folder_path);
  842 }
  843 
  844 static void
  845 mapi_ui_enable_actions (GtkActionGroup *action_group,
  846             const GtkActionEntry *entries,
  847             guint n_entries,
  848             gboolean can_show,
  849             gboolean is_online)
  850 {
  851     gint ii;
  852 
  853     g_return_if_fail (action_group != NULL);
  854     g_return_if_fail (entries != NULL);
  855 
  856     for (ii = 0; ii < n_entries; ii++) {
  857         GtkAction *action;
  858 
  859         action = gtk_action_group_get_action (action_group, entries[ii].name);
  860         if (!action)
  861             continue;
  862 
  863         gtk_action_set_visible (action, can_show);
  864         if (can_show)
  865             gtk_action_set_sensitive (action, is_online);
  866     }
  867 }
  868 
  869 static GtkActionEntry mail_account_context_entries[] = {
  870 
  871     { "mail-mapi-folder-size",
  872       NULL,
  873       N_("Folder size…"),
  874       NULL,
  875       NULL,  /* XXX Add a tooltip! */
  876       G_CALLBACK (action_folder_size_cb) },
  877 
  878     { "mail-mapi-subscribe-foreign-folder",
  879       NULL,
  880       N_("Subscribe to folder of other user…"),
  881       NULL,
  882       NULL,  /* XXX Add a tooltip! */
  883       G_CALLBACK (action_subscribe_foreign_folder_cb) }
  884 };
  885 
  886 static GtkActionEntry mail_folder_context_entries[] = {
  887     { "mail-mapi-folder-permissions",
  888       "folder-new",
  889       N_("Permissions…"),
  890       NULL,
  891       N_("Edit MAPI folder permissions"),
  892       G_CALLBACK (action_folder_permissions_mail_cb) }
  893 };
  894 
  895 static const gchar *mapi_ui_mail_def =
  896     "<menubar name='main-menu'>\n"
  897     "  <menu action='file-menu'>\n"
  898     "    <placeholder name='long-running-actions'>\n"
  899     "      <menuitem action=\"mapi-global-subscribe-foreign-folder\"/>\n"
  900     "    </placeholder>\n"
  901     "  </menu>\n"
  902     "</menubar>\n"
  903     "<popup name=\"mail-folder-popup\">\n"
  904     "  <placeholder name=\"mail-folder-popup-actions\">\n"
  905     "    <menuitem action=\"mail-mapi-folder-size\"/>\n"
  906     "    <menuitem action=\"mail-mapi-subscribe-foreign-folder\"/>\n"
  907     "    <menuitem action=\"mail-mapi-folder-permissions\"/>\n"
  908     "  </placeholder>\n"
  909     "</popup>\n";
  910 
  911 static void
  912 mapi_ui_update_actions_mail_cb (EShellView *shell_view,
  913                 GtkActionEntry *entries)
  914 {
  915     EShellWindow *shell_window;
  916     EShellBackend *backend;
  917     CamelSession *session = NULL;
  918     GtkActionGroup *action_group;
  919     GtkUIManager *ui_manager;
  920     EShellSidebar *shell_sidebar;
  921     EMFolderTree *folder_tree;
  922     CamelStore *selected_store = NULL;
  923     gchar *selected_path = NULL;
  924     gboolean account_node = FALSE, folder_node = FALSE;
  925     gboolean online, has_mapi_account;
  926 
  927     shell_sidebar = e_shell_view_get_shell_sidebar (shell_view);
  928     g_object_get (shell_sidebar, "folder-tree", &folder_tree, NULL);
  929     if (em_folder_tree_get_selected (folder_tree, &selected_store, &selected_path) ||
  930         em_folder_tree_store_root_selected (folder_tree, &selected_store)) {
  931         if (selected_store) {
  932             CamelProvider *provider = camel_service_get_provider (CAMEL_SERVICE (selected_store));
  933 
  934             if (provider && g_ascii_strcasecmp (provider->protocol, "mapi") == 0) {
  935                 account_node = !selected_path || !*selected_path;
  936                 folder_node = !account_node;
  937             }
  938 
  939             g_object_unref (selected_store);
  940         }
  941     }
  942     g_object_unref (folder_tree);
  943 
  944     g_free (selected_path);
  945 
  946     shell_window = e_shell_view_get_shell_window (shell_view);
  947     ui_manager = e_shell_window_get_ui_manager (shell_window);
  948     action_group = e_lookup_action_group (ui_manager, "mail");
  949 
  950     backend = e_shell_view_get_shell_backend (shell_view);
  951     g_object_get (G_OBJECT (backend), "session", &session, NULL);
  952 
  953     online = session && camel_session_get_online (session);
  954 
  955     has_mapi_account = account_node || folder_node || mapi_ui_has_mapi_account (shell_view, session);
  956 
  957     if (session)
  958         g_object_unref (session);
  959 
  960     mapi_ui_enable_actions (action_group, mail_account_context_entries, G_N_ELEMENTS (mail_account_context_entries), account_node, online);
  961     mapi_ui_enable_actions (action_group, mail_folder_context_entries, G_N_ELEMENTS (mail_folder_context_entries), folder_node, online);
  962     mapi_ui_enable_actions (action_group, global_mapi_entries, G_N_ELEMENTS (global_mapi_entries), has_mapi_account, online);
  963 }
  964 
  965 static void
  966 mapi_ui_init_mail (GtkUIManager *ui_manager,
  967                    EShellView *shell_view,
  968            gchar **ui_definition)
  969 {
  970     EShellWindow *shell_window;
  971     GtkActionGroup *action_group;
  972 
  973     g_return_if_fail (ui_definition != NULL);
  974 
  975     *ui_definition = g_strdup (mapi_ui_mail_def);
  976 
  977     shell_window = e_shell_view_get_shell_window (shell_view);
  978     action_group = e_shell_window_get_action_group (shell_window, "mail");
  979 
  980     /* Add actions to the "mail" action group. */
  981     e_action_group_add_actions_localized (action_group, GETTEXT_PACKAGE,
  982         mail_account_context_entries, G_N_ELEMENTS (mail_account_context_entries), shell_view);
  983     e_action_group_add_actions_localized (action_group, GETTEXT_PACKAGE,
  984         mail_folder_context_entries, G_N_ELEMENTS (mail_folder_context_entries), shell_view);
  985 
  986     /* Add global actions */
  987     e_action_group_add_actions_localized (
  988         action_group, GETTEXT_PACKAGE,
  989         global_mapi_entries, G_N_ELEMENTS (global_mapi_entries), shell_view);
  990 
  991     /* Decide whether we want this option to be visible or not */
  992     g_signal_connect (shell_view, "update-actions",
  993               G_CALLBACK (mapi_ui_update_actions_mail_cb),
  994               shell_view);
  995 }
  996 
  997 static gboolean
  998 get_selected_mapi_source (EShellView *shell_view,
  999               ESource **selected_source,
 1000               ESourceRegistry **registry)
 1001 {
 1002     ESource *source;
 1003     EShellSidebar *shell_sidebar;
 1004     ESourceSelector *selector = NULL;
 1005 
 1006     g_return_val_if_fail (shell_view != NULL, FALSE);
 1007 
 1008     shell_sidebar = e_shell_view_get_shell_sidebar (shell_view);
 1009     g_return_val_if_fail (shell_sidebar != NULL, FALSE);
 1010 
 1011     g_object_get (shell_sidebar, "selector", &selector, NULL);
 1012     g_return_val_if_fail (selector != NULL, FALSE);
 1013 
 1014     source = e_source_selector_ref_primary_selection (selector);
 1015     if (source) {
 1016         ESourceBackend *backend_ext = NULL;
 1017 
 1018         if (e_source_has_extension (source, E_SOURCE_EXTENSION_ADDRESS_BOOK))
 1019             backend_ext = e_source_get_extension (source, E_SOURCE_EXTENSION_ADDRESS_BOOK);
 1020         else if (e_source_has_extension (source, E_SOURCE_EXTENSION_CALENDAR))
 1021             backend_ext = e_source_get_extension (source, E_SOURCE_EXTENSION_CALENDAR);
 1022         else if (e_source_has_extension (source, E_SOURCE_EXTENSION_MEMO_LIST))
 1023             backend_ext = e_source_get_extension (source, E_SOURCE_EXTENSION_MEMO_LIST);
 1024         else if (e_source_has_extension (source, E_SOURCE_EXTENSION_TASK_LIST))
 1025             backend_ext = e_source_get_extension (source, E_SOURCE_EXTENSION_TASK_LIST);
 1026         else if (e_source_has_extension (source, E_SOURCE_EXTENSION_MAIL_ACCOUNT))
 1027             backend_ext = e_source_get_extension (source, E_SOURCE_EXTENSION_MAIL_ACCOUNT);
 1028 
 1029         if (!backend_ext ||
 1030             g_strcmp0 (e_source_backend_get_backend_name (backend_ext), "mapi") != 0) {
 1031             g_object_unref (source);
 1032             source = NULL;
 1033         }
 1034     }
 1035 
 1036     if (source && registry)
 1037         *registry = g_object_ref (e_source_selector_get_registry (selector));
 1038 
 1039     g_object_unref (selector);
 1040 
 1041     if (selected_source)
 1042         *selected_source = source;
 1043     else if (source)
 1044         g_object_unref (source);
 1045 
 1046     return source != NULL;
 1047 }
 1048 
 1049 /* how many menu entries are defined; all calendar/tasks/memos/contacts
 1050    actions should have same count */
 1051 #define MAPI_ESOURCE_NUM_ENTRIES 1
 1052 
 1053 static void
 1054 update_mapi_source_entries_cb (EShellView *shell_view,
 1055                    GtkActionEntry *entries)
 1056 {
 1057     GtkActionGroup *action_group;
 1058     EShell *shell;
 1059     EShellWindow *shell_window;
 1060     ESource *source = NULL;
 1061     const gchar *group;
 1062     gboolean is_mapi_source, is_online;
 1063 
 1064     g_return_if_fail (E_IS_SHELL_VIEW (shell_view));
 1065     g_return_if_fail (entries != NULL);
 1066 
 1067     if (strstr (entries->name, "calendar"))
 1068         group = "calendar";
 1069     else if (strstr (entries->name, "tasks"))
 1070         group = "tasks";
 1071     else if (strstr (entries->name, "memos"))
 1072         group = "memos";
 1073     else if (strstr (entries->name, "contacts"))
 1074         group = "contacts";
 1075     else
 1076         g_return_if_reached ();
 1077 
 1078     is_mapi_source = get_selected_mapi_source (shell_view, &source, NULL);
 1079 
 1080     if (is_mapi_source) {
 1081         ESource *clicked_source = NULL;
 1082 
 1083         g_object_get (G_OBJECT (shell_view), "clicked-source", &clicked_source, NULL);
 1084 
 1085         if (clicked_source && clicked_source != source)
 1086             is_mapi_source = FALSE;
 1087 
 1088         g_clear_object (&clicked_source);
 1089     }
 1090 
 1091     g_clear_object (&source);
 1092 
 1093     shell_window = e_shell_view_get_shell_window (shell_view);
 1094     shell = e_shell_window_get_shell (shell_window);
 1095 
 1096     is_online = shell && e_shell_get_online (shell);
 1097     action_group = e_shell_window_get_action_group (shell_window, group);
 1098 
 1099     mapi_ui_enable_actions (action_group, entries, MAPI_ESOURCE_NUM_ENTRIES, is_mapi_source, is_online);
 1100     mapi_ui_enable_actions (action_group, global_mapi_entries, G_N_ELEMENTS (global_mapi_entries),
 1101         mapi_ui_has_mapi_account (shell_view, NULL), is_online);
 1102 }
 1103 
 1104 static void
 1105 setup_mapi_source_actions (EShellView *shell_view,
 1106                GtkUIManager *ui_manager,
 1107                GtkActionEntry *entries,
 1108                guint n_entries)
 1109 {
 1110     EShellWindow *shell_window;
 1111     GtkActionGroup *action_group;
 1112     const gchar *group;
 1113 
 1114     g_return_if_fail (shell_view != NULL);
 1115     g_return_if_fail (ui_manager != NULL);
 1116     g_return_if_fail (entries != NULL);
 1117     g_return_if_fail (n_entries > 0);
 1118     g_return_if_fail (n_entries == MAPI_ESOURCE_NUM_ENTRIES);
 1119 
 1120     if (strstr (entries->name, "calendar"))
 1121         group = "calendar";
 1122     else if (strstr (entries->name, "tasks"))
 1123         group = "tasks";
 1124     else if (strstr (entries->name, "memos"))
 1125         group = "memos";
 1126     else if (strstr (entries->name, "contacts"))
 1127         group = "contacts";
 1128     else
 1129         g_return_if_reached ();
 1130 
 1131     shell_window = e_shell_view_get_shell_window (shell_view);
 1132     action_group = e_shell_window_get_action_group (shell_window, group);
 1133 
 1134     e_action_group_add_actions_localized (
 1135         action_group, GETTEXT_PACKAGE,
 1136         entries, MAPI_ESOURCE_NUM_ENTRIES, shell_view);
 1137 
 1138     /* Add global actions */
 1139     e_action_group_add_actions_localized (
 1140         action_group, GETTEXT_PACKAGE,
 1141         global_mapi_entries, G_N_ELEMENTS (global_mapi_entries), shell_view);
 1142 
 1143     g_signal_connect (shell_view, "update-actions", G_CALLBACK (update_mapi_source_entries_cb), entries);
 1144 }
 1145 
 1146 static void
 1147 action_folder_permissions_source_cb (GtkAction *action,
 1148                      EShellView *shell_view)
 1149 {
 1150     ESourceRegistry *registry = NULL;
 1151     ESource *source = NULL, *parent_source;
 1152     ESourceMapiFolder *folder_ext;
 1153     mapi_id_t folder_id = 0;
 1154     const gchar *foreign_username;
 1155     gboolean is_public;
 1156     ESourceCamel *extension;
 1157     CamelSettings *settings;
 1158     const gchar *extension_name;
 1159 
 1160     g_return_if_fail (action != NULL);
 1161     g_return_if_fail (shell_view != NULL);
 1162     g_return_if_fail (get_selected_mapi_source (shell_view, &source, &registry));
 1163     g_return_if_fail (source != NULL);
 1164     g_return_if_fail (e_source_has_extension (source, E_SOURCE_EXTENSION_MAPI_FOLDER));
 1165     g_return_if_fail (gtk_action_get_name (action) != NULL);
 1166 
 1167     folder_ext = e_source_get_extension (source, E_SOURCE_EXTENSION_MAPI_FOLDER);
 1168     folder_id = e_source_mapi_folder_get_id (folder_ext);
 1169     g_return_if_fail (folder_id != 0);
 1170 
 1171     foreign_username = e_source_mapi_folder_get_foreign_username (folder_ext);
 1172     is_public = !foreign_username && e_source_mapi_folder_is_public (folder_ext);
 1173 
 1174     parent_source = e_source_registry_ref_source (registry, e_source_get_parent (source));
 1175 
 1176     extension_name = e_source_camel_get_extension_name ("mapi");
 1177     extension = e_source_get_extension (parent_source, extension_name);
 1178 
 1179     settings = e_source_camel_get_settings (extension);
 1180 
 1181     e_mapi_edit_folder_permissions (NULL,
 1182         registry,
 1183         source,
 1184         CAMEL_MAPI_SETTINGS (settings),
 1185         e_source_get_display_name (parent_source),
 1186         e_source_get_display_name (source),
 1187         folder_id,
 1188         foreign_username ? E_MAPI_FOLDER_CATEGORY_FOREIGN :
 1189         is_public ? E_MAPI_FOLDER_CATEGORY_PUBLIC :
 1190         E_MAPI_FOLDER_CATEGORY_PERSONAL,
 1191         foreign_username,
 1192         strstr (gtk_action_get_name (action), "calendar") != NULL);
 1193 
 1194     g_object_unref (source);
 1195     g_object_unref (parent_source);
 1196     g_object_unref (registry);
 1197 }
 1198 
 1199 static GtkActionEntry calendar_context_entries[] = {
 1200 
 1201     { "calendar-mapi-folder-permissions",
 1202       "folder-new",
 1203       N_("Permissions…"),
 1204       NULL,
 1205       N_("Edit MAPI calendar permissions"),
 1206       G_CALLBACK (action_folder_permissions_source_cb) }
 1207 };
 1208 
 1209 static const gchar *mapi_ui_cal_def =
 1210     "<menubar name='main-menu'>\n"
 1211     "  <menu action='file-menu'>\n"
 1212     "    <placeholder name='long-running-actions'>\n"
 1213     "      <menuitem action=\"mapi-global-subscribe-foreign-folder\"/>\n"
 1214     "    </placeholder>\n"
 1215     "  </menu>\n"
 1216     "</menubar>\n"
 1217     "<popup name=\"calendar-popup\">\n"
 1218     "  <placeholder name=\"calendar-popup-actions\">\n"
 1219     "    <menuitem action=\"calendar-mapi-folder-permissions\"/>\n"
 1220     "  </placeholder>\n"
 1221     "</popup>\n";
 1222 
 1223 static void
 1224 mapi_ui_init_calendar (GtkUIManager *ui_manager,
 1225                EShellView *shell_view,
 1226                gchar **ui_definition)
 1227 {
 1228     g_return_if_fail (ui_definition != NULL);
 1229 
 1230     *ui_definition = g_strdup (mapi_ui_cal_def);
 1231 
 1232     setup_mapi_source_actions (shell_view, ui_manager,
 1233         calendar_context_entries, G_N_ELEMENTS (calendar_context_entries));
 1234 }
 1235 
 1236 static GtkActionEntry tasks_context_entries[] = {
 1237 
 1238     { "tasks-mapi-folder-permissions",
 1239       "folder-new",
 1240       N_("Permissions…"),
 1241       NULL,
 1242       N_("Edit MAPI tasks permissions"),
 1243       G_CALLBACK (action_folder_permissions_source_cb) }
 1244 };
 1245 
 1246 static const gchar *mapi_ui_task_def =
 1247     "<menubar name='main-menu'>\n"
 1248     "  <menu action='file-menu'>\n"
 1249     "    <placeholder name='long-running-actions'>\n"
 1250     "      <menuitem action=\"mapi-global-subscribe-foreign-folder\"/>\n"
 1251     "    </placeholder>\n"
 1252     "  </menu>\n"
 1253     "</menubar>\n"
 1254     "<popup name=\"task-list-popup\">\n"
 1255     "  <placeholder name=\"task-list-popup-actions\">\n"
 1256     "    <menuitem action=\"tasks-mapi-folder-permissions\"/>\n"
 1257     "  </placeholder>\n"
 1258     "</popup>\n";
 1259 
 1260 static void
 1261 mapi_ui_init_tasks (GtkUIManager *ui_manager,
 1262             EShellView *shell_view,
 1263             gchar **ui_definition)
 1264 {
 1265     g_return_if_fail (ui_definition != NULL);
 1266 
 1267     *ui_definition = g_strdup (mapi_ui_task_def);
 1268 
 1269     setup_mapi_source_actions (shell_view, ui_manager,
 1270         tasks_context_entries, G_N_ELEMENTS (tasks_context_entries));
 1271 }
 1272 
 1273 static GtkActionEntry memos_context_entries[] = {
 1274 
 1275     { "memos-mapi-folder-permissions",
 1276       "folder-new",
 1277       N_("Permissions…"),
 1278       NULL,
 1279       N_("Edit MAPI memos permissions"),
 1280       G_CALLBACK (action_folder_permissions_source_cb) }
 1281 };
 1282 
 1283 static const gchar *mapi_ui_memo_def =
 1284     "<menubar name='main-menu'>\n"
 1285     "  <menu action='file-menu'>\n"
 1286     "    <placeholder name='long-running-actions'>\n"
 1287     "      <menuitem action=\"mapi-global-subscribe-foreign-folder\"/>\n"
 1288     "    </placeholder>\n"
 1289     "  </menu>\n"
 1290     "</menubar>\n"
 1291     "<popup name=\"memo-list-popup\">\n"
 1292     "  <placeholder name=\"memo-list-popup-actions\">\n"
 1293     "    <menuitem action=\"memos-mapi-folder-permissions\"/>\n"
 1294     "  </placeholder>\n"
 1295     "</popup>\n";
 1296 
 1297 static void
 1298 mapi_ui_init_memos (GtkUIManager *ui_manager,
 1299             EShellView *shell_view,
 1300             gchar **ui_definition)
 1301 {
 1302     g_return_if_fail (ui_definition != NULL);
 1303 
 1304     *ui_definition = g_strdup (mapi_ui_memo_def);
 1305 
 1306     setup_mapi_source_actions (shell_view, ui_manager,
 1307         memos_context_entries, G_N_ELEMENTS (memos_context_entries));
 1308 }
 1309 
 1310 static GtkActionEntry contacts_context_entries[] = {
 1311 
 1312     { "contacts-mapi-folder-permissions",
 1313       "folder-new",
 1314       N_("Permissions…"),
 1315       NULL,
 1316       N_("Edit MAPI contacts permissions"),
 1317       G_CALLBACK (action_folder_permissions_source_cb) }
 1318 };
 1319 
 1320 static const gchar *mapi_ui_book_def =
 1321     "<menubar name='main-menu'>\n"
 1322     "  <menu action='file-menu'>\n"
 1323     "    <placeholder name='long-running-actions'>\n"
 1324     "      <menuitem action=\"mapi-global-subscribe-foreign-folder\"/>\n"
 1325     "    </placeholder>\n"
 1326     "  </menu>\n"
 1327     "</menubar>\n"
 1328     "<popup name=\"address-book-popup\">\n"
 1329     "  <placeholder name=\"address-book-popup-actions\">\n"
 1330     "    <menuitem action=\"contacts-mapi-folder-permissions\"/>\n"
 1331     "  </placeholder>\n"
 1332     "</popup>\n";
 1333 
 1334 static void
 1335 mapi_ui_init_contacts (GtkUIManager *ui_manager,
 1336                EShellView *shell_view,
 1337                gchar **ui_definition)
 1338 {
 1339     g_return_if_fail (ui_definition != NULL);
 1340 
 1341     *ui_definition = g_strdup (mapi_ui_book_def);
 1342 
 1343     setup_mapi_source_actions (shell_view, ui_manager,
 1344         contacts_context_entries, G_N_ELEMENTS (contacts_context_entries));
 1345 }
 1346 
 1347 void
 1348 e_mapi_config_utils_init_ui (EShellView *shell_view,
 1349                  const gchar *ui_manager_id,
 1350                  gchar **ui_definition)
 1351 {
 1352     EShellWindow *shell_window;
 1353     GtkUIManager *ui_manager;
 1354 
 1355     g_return_if_fail (shell_view != NULL);
 1356     g_return_if_fail (ui_manager_id != NULL);
 1357     g_return_if_fail (ui_definition != NULL);
 1358 
 1359     shell_window = e_shell_view_get_shell_window (shell_view);
 1360     ui_manager = e_shell_window_get_ui_manager (shell_window);
 1361 
 1362     if (g_strcmp0 (ui_manager_id, "org.gnome.evolution.mail") == 0)
 1363         mapi_ui_init_mail (ui_manager, shell_view, ui_definition);
 1364     else if (g_strcmp0 (ui_manager_id, "org.gnome.evolution.calendars") == 0)
 1365         mapi_ui_init_calendar (ui_manager, shell_view, ui_definition);
 1366     else if (g_strcmp0 (ui_manager_id, "org.gnome.evolution.tasks") == 0)
 1367         mapi_ui_init_tasks (ui_manager, shell_view, ui_definition);
 1368     else if (g_strcmp0 (ui_manager_id, "org.gnome.evolution.memos") == 0)
 1369         mapi_ui_init_memos (ui_manager, shell_view, ui_definition);
 1370     else if (g_strcmp0 (ui_manager_id, "org.gnome.evolution.contacts") == 0)
 1371         mapi_ui_init_contacts (ui_manager, shell_view, ui_definition);
 1372 }
 1373 
 1374 gboolean
 1375 e_mapi_config_utils_is_online (void)
 1376 {
 1377     EShell *shell;
 1378 
 1379     shell = e_shell_get_default ();
 1380 
 1381     return shell && e_shell_get_online (shell);
 1382 }
 1383 
 1384 GtkWindow *
 1385 e_mapi_config_utils_get_widget_toplevel_window (GtkWidget *widget)
 1386 {
 1387     if (!widget)
 1388         return NULL;
 1389 
 1390     if (!GTK_IS_WINDOW (widget))
 1391         widget = gtk_widget_get_toplevel (widget);
 1392 
 1393     if (GTK_IS_WINDOW (widget))
 1394         return GTK_WINDOW (widget);
 1395 
 1396     return NULL;
 1397 }
 1398 
 1399 enum {
 1400     NAME_COL,
 1401     FID_COL,
 1402     FOLDER_COL,
 1403     NUM_COLS
 1404 };
 1405 
 1406 static gboolean
 1407 check_node (GtkTreeStore *ts, EMapiFolder *folder, GtkTreeIter iter)
 1408 {
 1409     GtkTreeModel *ts_model;
 1410     mapi_id_t fid;
 1411 
 1412     ts_model = GTK_TREE_MODEL (ts);
 1413 
 1414     gtk_tree_model_get (ts_model, &iter, 1, &fid, -1);
 1415     if (fid && folder->parent_folder_id == fid) {
 1416         /* Do something */
 1417         GtkTreeIter node;
 1418         gtk_tree_store_append (ts, &node, &iter);
 1419         gtk_tree_store_set (ts, &node, NAME_COL, folder->folder_name, FID_COL, folder->folder_id, FOLDER_COL, folder,-1);
 1420         return TRUE;
 1421     }
 1422 
 1423     if (gtk_tree_model_iter_has_child (ts_model, &iter)) {
 1424         GtkTreeIter child;
 1425         gtk_tree_model_iter_children (ts_model, &child, &iter);
 1426         if (check_node (ts, folder, child))
 1427             return TRUE;
 1428     }
 1429 
 1430     if (gtk_tree_model_iter_next (ts_model, &iter)) {
 1431         return check_node (ts, folder, iter);
 1432     }
 1433 
 1434     return FALSE;
 1435 }
 1436 
 1437 static void
 1438 add_to_store (GtkTreeStore *ts, EMapiFolder *folder)
 1439 {
 1440     GtkTreeModel *ts_model;
 1441     GtkTreeIter iter;
 1442 
 1443     ts_model = GTK_TREE_MODEL (ts);
 1444 
 1445     g_return_if_fail (gtk_tree_model_get_iter_first (ts_model, &iter));
 1446     if (!check_node (ts, folder, iter)) {
 1447         GtkTreeIter node;
 1448         gtk_tree_store_append (ts, &node, &iter);
 1449         gtk_tree_store_set (ts, &node, NAME_COL, folder->folder_name, FID_COL, folder->folder_id, FOLDER_COL, folder, -1);
 1450     }
 1451 }
 1452 
 1453 static void
 1454 traverse_tree (GtkTreeModel *model, GtkTreeIter iter, EMapiFolderType folder_type, gboolean *pany_sub_used)
 1455 {
 1456     gboolean any_sub_used = FALSE;
 1457     gboolean has_next = TRUE;
 1458 
 1459     do {
 1460         gboolean sub_used = FALSE;
 1461         GtkTreeIter next = iter;
 1462         EMapiFolder *folder = NULL;
 1463 
 1464         has_next = gtk_tree_model_iter_next (model, &next);
 1465 
 1466         if (gtk_tree_model_iter_has_child (model, &iter)) {
 1467             GtkTreeIter child;
 1468 
 1469             gtk_tree_model_iter_children (model, &child, &iter);
 1470             traverse_tree (model, child, folder_type, &sub_used);
 1471         }
 1472 
 1473         gtk_tree_model_get (model, &iter, FOLDER_COL, &folder, -1);
 1474         if (folder && (e_mapi_folder_get_type (folder) == folder_type || (folder_type == E_MAPI_FOLDER_TYPE_MEMO && e_mapi_folder_get_type (folder) == E_MAPI_FOLDER_TYPE_JOURNAL))) {
 1475             sub_used = TRUE;
 1476         }
 1477 
 1478         if (sub_used)
 1479             any_sub_used = TRUE;
 1480         else if (pany_sub_used && folder)
 1481             gtk_tree_store_remove (GTK_TREE_STORE (model), &iter);
 1482 
 1483         iter = next;
 1484     } while (has_next);
 1485 
 1486     if (pany_sub_used && any_sub_used)
 1487         *pany_sub_used = TRUE;
 1488 }
 1489 
 1490 static void
 1491 add_folders (GSList *folders, GtkTreeStore *ts, EMapiFolderType folder_type)
 1492 {
 1493     GSList *tmp = folders;
 1494     GtkTreeIter iter;
 1495     GtkTreeModel *model = GTK_TREE_MODEL (ts);
 1496     gchar *node = _("Personal Folders");
 1497 
 1498     /* add all... */
 1499     gtk_tree_store_append (ts, &iter, NULL);
 1500     gtk_tree_store_set (ts, &iter, NAME_COL, node, -1);
 1501     while (tmp) {
 1502         EMapiFolder *folder = tmp->data;
 1503         add_to_store (ts, folder);
 1504         tmp = tmp->next;
 1505     }
 1506 
 1507     /* ... then remove those which don't belong to folder_type */
 1508     if (gtk_tree_model_get_iter_first (model, &iter)) {
 1509         traverse_tree (model, iter, folder_type, NULL);
 1510     }
 1511 }
 1512 
 1513 static void
 1514 select_folder (GtkTreeModel *model,
 1515            mapi_id_t fid,
 1516            GtkWidget *tree_view)
 1517 {
 1518     GtkTreeIter iter, next;
 1519     gboolean found = FALSE, can = TRUE;
 1520 
 1521     g_return_if_fail (model != NULL);
 1522     g_return_if_fail (tree_view != NULL);
 1523 
 1524     if (!gtk_tree_model_get_iter_first (model, &iter))
 1525         return;
 1526 
 1527     while (!found && can) {
 1528         EMapiFolder *folder = NULL;
 1529 
 1530         gtk_tree_model_get (model, &iter, FOLDER_COL, &folder, -1);
 1531 
 1532         if (folder && e_mapi_folder_get_id (folder) == fid) {
 1533             gtk_tree_selection_select_iter (gtk_tree_view_get_selection (GTK_TREE_VIEW (tree_view)), &iter);
 1534             found = TRUE;
 1535             break;
 1536         }
 1537 
 1538         can = FALSE;
 1539         if (gtk_tree_model_iter_children (model, &next, &iter)) {
 1540             iter = next;
 1541             can = TRUE;
 1542         }
 1543 
 1544         next = iter;
 1545         if (!can && gtk_tree_model_iter_next (model, &next)) {
 1546             iter = next;
 1547             can = TRUE;
 1548         }
 1549 
 1550         if (!can && gtk_tree_model_iter_parent (model, &next, &iter)) {
 1551             while (!can) {
 1552                 iter = next;
 1553 
 1554                 if (gtk_tree_model_iter_next (model, &iter)) {
 1555                     can = TRUE;
 1556                     break;
 1557                 }
 1558 
 1559                 iter = next;
 1560                 if (!gtk_tree_model_iter_parent (model, &next, &iter))
 1561                     break;
 1562             }
 1563         }
 1564     }
 1565 }
 1566 
 1567 static void
 1568 e_mapi_cursor_change (GtkTreeView *treeview,
 1569               ESource *source)
 1570 {
 1571     ESourceMapiFolder *folder_ext;
 1572     GtkTreeSelection *selection;
 1573     GtkTreeModel *model;
 1574     GtkTreeIter iter;
 1575     mapi_id_t pfid;
 1576 
 1577     selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (treeview));
 1578     if (!selection)
 1579         return;
 1580 
 1581     if (gtk_tree_selection_get_selected (selection, &model, &iter)) {
 1582         gtk_tree_model_get (model, &iter, FID_COL, &pfid, -1);
 1583     } else {
 1584         pfid = 0;
 1585     }
 1586 
 1587     folder_ext = e_source_get_extension (source, E_SOURCE_EXTENSION_MAPI_FOLDER);
 1588     e_source_mapi_folder_set_parent_id (folder_ext, pfid);
 1589 }
 1590 
 1591 struct EMapiFolderStructureData
 1592 {
 1593     EMapiFolderType folder_type;
 1594     GSList *folders;
 1595     GtkWidget *tree_view;
 1596     ESource *source;
 1597     ESource *child_source;
 1598     ESourceRegistry *registry;
 1599     ESourceConfig *config;
 1600 };
 1601 
 1602 static void
 1603 e_mapi_folder_structure_data_free (gpointer ptr)
 1604 {
 1605     struct EMapiFolderStructureData *fsd = ptr;
 1606 
 1607     if (!fsd)
 1608         return;
 1609 
 1610     e_mapi_folder_free_list (fsd->folders);
 1611     g_object_unref (fsd->tree_view);
 1612     if (fsd->source)
 1613         g_object_unref (fsd->source);
 1614     if (fsd->config)
 1615         g_object_unref (fsd->config);
 1616     g_object_unref (fsd->child_source);
 1617     g_object_unref (fsd->registry);
 1618     g_slice_free (struct EMapiFolderStructureData, fsd);
 1619 }
 1620 
 1621 static void
 1622 e_mapi_download_folder_structure_idle (GObject *source_obj,
 1623                        gpointer user_data,
 1624                        GCancellable *cancellable,
 1625                        GError **perror)
 1626 {
 1627     struct EMapiFolderStructureData *fsd = user_data;
 1628     ESourceMapiFolder *folder_ext;
 1629     GtkTreeStore *tree_store;
 1630 
 1631     g_return_if_fail (fsd != NULL);
 1632     g_return_if_fail (fsd->tree_view != NULL);
 1633     g_return_if_fail (source_obj != NULL);
 1634     g_return_if_fail (E_IS_SOURCE (source_obj));
 1635 
 1636     tree_store = GTK_TREE_STORE (gtk_tree_view_get_model (GTK_TREE_VIEW (fsd->tree_view)));
 1637     g_return_if_fail (tree_store != NULL);
 1638 
 1639     add_folders (fsd->folders, tree_store, fsd->folder_type);
 1640     gtk_tree_view_expand_all (GTK_TREE_VIEW (fsd->tree_view));
 1641 
 1642     folder_ext = e_source_get_extension (fsd->child_source, E_SOURCE_EXTENSION_MAPI_FOLDER);
 1643     if (e_source_mapi_folder_get_id (folder_ext)) {
 1644         select_folder (GTK_TREE_MODEL (tree_store),
 1645             e_source_mapi_folder_get_id (folder_ext),
 1646             fsd->tree_view);
 1647     }
 1648 }
 1649 
 1650 static void
 1651 e_mapi_download_folder_structure_thread (GObject *source_obj,
 1652                      gpointer user_data,
 1653                      GCancellable *cancellable,
 1654                      GError **perror)
 1655 {
 1656     struct EMapiFolderStructureData *fsd = user_data;
 1657     const gchar *extension_name;
 1658     ESource *source;
 1659     ESourceCamel *extension;
 1660     EMapiConnection *conn;
 1661     CamelSettings *settings;
 1662 
 1663     g_return_if_fail (fsd != NULL);
 1664     g_return_if_fail (fsd->tree_view != NULL);
 1665     g_return_if_fail (source_obj != NULL);
 1666     g_return_if_fail (E_IS_SOURCE (source_obj));
 1667 
 1668     source = E_SOURCE (source_obj);
 1669 
 1670     extension_name = e_source_camel_get_extension_name ("mapi");
 1671     g_return_if_fail (e_source_has_extension (source, extension_name));
 1672 
 1673     extension = e_source_get_extension (source, extension_name);
 1674 
 1675     settings = e_source_camel_get_settings (extension);
 1676 
 1677     conn = e_mapi_config_utils_open_connection_for (NULL,
 1678         fsd->registry,
 1679         source,
 1680         CAMEL_MAPI_SETTINGS (settings),
 1681         cancellable,
 1682         perror);
 1683 
 1684     if (!conn)
 1685         return;
 1686 
 1687     if (conn && e_mapi_connection_connected (conn)) {
 1688         fsd->folders = e_mapi_connection_peek_folders_list (conn);
 1689         if (fsd->folders)
 1690             fsd->folders = e_mapi_folder_copy_list (fsd->folders);
 1691     }
 1692 
 1693     if (conn)
 1694         g_object_unref (conn);
 1695 }
 1696 
 1697 static void
 1698 tree_view_mapped_cb (GObject *tree_view)
 1699 {
 1700     const struct EMapiFolderStructureData *old_fsd = g_object_get_data (tree_view, "mapi-fsd-pointer");
 1701     struct EMapiFolderStructureData *fsd;
 1702     GtkTreeViewColumn *column;
 1703     ESource *parent_source;
 1704 
 1705     g_return_if_fail (old_fsd != NULL);
 1706 
 1707     parent_source = e_source_config_get_collection_source (old_fsd->config);
 1708     if (!parent_source)
 1709         parent_source = e_source_registry_find_extension (
 1710             old_fsd->registry, old_fsd->child_source, E_SOURCE_EXTENSION_COLLECTION);
 1711 
 1712     g_return_if_fail (parent_source != NULL);
 1713 
 1714     fsd = g_slice_new0 (struct EMapiFolderStructureData);
 1715     fsd->folder_type = old_fsd->folder_type;
 1716     fsd->folders = NULL;
 1717     fsd->tree_view = g_object_ref (old_fsd->tree_view);
 1718     fsd->source = g_object_ref (parent_source);
 1719     fsd->child_source = g_object_ref (old_fsd->child_source);
 1720     fsd->registry = g_object_ref (old_fsd->registry);
 1721 
 1722     column = gtk_tree_view_get_column (GTK_TREE_VIEW (tree_view), 0);
 1723     gtk_tree_view_column_set_title (column, e_source_get_display_name (parent_source));
 1724 
 1725     e_mapi_config_utils_run_in_thread_with_feedback (e_mapi_config_utils_get_widget_toplevel_window (fsd->tree_view),
 1726         G_OBJECT (fsd->source),
 1727         _("Searching remote MAPI folder structure, please wait…"),
 1728         e_mapi_download_folder_structure_thread,
 1729         e_mapi_download_folder_structure_idle,
 1730         fsd,
 1731         e_mapi_folder_structure_data_free);
 1732 }
 1733 
 1734 void
 1735 e_mapi_config_utils_insert_widgets (ESourceConfigBackend *backend,
 1736                     ESource *scratch_source)
 1737 {
 1738     ESourceBackend *backend_ext = NULL;
 1739     ESourceMapiFolder *folder_ext;
 1740     ESourceConfig *config;
 1741     GtkWidget *widget;
 1742     gboolean is_new_source;
 1743     EMapiFolderType folder_type = E_MAPI_FOLDER_TYPE_UNKNOWN;
 1744 
 1745     g_return_if_fail (backend != NULL);
 1746     g_return_if_fail (scratch_source != NULL);
 1747 
 1748     if (e_source_has_extension (scratch_source, E_SOURCE_EXTENSION_ADDRESS_BOOK)) {
 1749         backend_ext = e_source_get_extension (scratch_source, E_SOURCE_EXTENSION_ADDRESS_BOOK);
 1750         folder_type = E_MAPI_FOLDER_TYPE_CONTACT;
 1751     } else if (e_source_has_extension (scratch_source, E_SOURCE_EXTENSION_CALENDAR)) {
 1752         backend_ext = e_source_get_extension (scratch_source, E_SOURCE_EXTENSION_CALENDAR);
 1753         folder_type = E_MAPI_FOLDER_TYPE_APPOINTMENT;
 1754     } else if (e_source_has_extension (scratch_source, E_SOURCE_EXTENSION_TASK_LIST)) {
 1755         backend_ext = e_source_get_extension (scratch_source, E_SOURCE_EXTENSION_TASK_LIST);
 1756         folder_type = E_MAPI_FOLDER_TYPE_TASK;
 1757     } else if (e_source_has_extension (scratch_source, E_SOURCE_EXTENSION_MEMO_LIST)) {
 1758         backend_ext = e_source_get_extension (scratch_source, E_SOURCE_EXTENSION_MEMO_LIST);
 1759         folder_type = E_MAPI_FOLDER_TYPE_MEMO;
 1760     }
 1761 
 1762     if (!backend_ext || g_strcmp0 (e_source_backend_get_backend_name (backend_ext), "mapi") != 0)
 1763         return;
 1764 
 1765     folder_ext = e_source_get_extension (scratch_source, E_SOURCE_EXTENSION_MAPI_FOLDER);
 1766     g_return_if_fail (folder_ext != NULL);
 1767 
 1768     config = e_source_config_backend_get_config (backend);
 1769     if (E_IS_BOOK_SOURCE_CONFIG (config))
 1770         e_book_source_config_add_offline_toggle (E_BOOK_SOURCE_CONFIG (config), scratch_source);
 1771     else if (E_IS_CAL_SOURCE_CONFIG (config))
 1772         e_cal_source_config_add_offline_toggle (E_CAL_SOURCE_CONFIG (config), scratch_source);
 1773 
 1774     widget = gtk_check_button_new_with_mnemonic (_("Lis_ten for server notifications"));
 1775     e_source_config_insert_widget (config, scratch_source, NULL, widget);
 1776     gtk_widget_show (widget);
 1777 
 1778     e_binding_bind_property (
 1779         folder_ext, "server-notification",
 1780         widget, "active",
 1781         G_BINDING_BIDIRECTIONAL |
 1782         G_BINDING_SYNC_CREATE);
 1783 
 1784     /* no extra options for subscribed folders */
 1785     if (e_source_mapi_folder_is_public (folder_ext) ||
 1786         e_source_mapi_folder_get_foreign_username (folder_ext)) {
 1787         e_source_config_add_refresh_interval (config, scratch_source);
 1788         return;
 1789     }
 1790 
 1791     is_new_source = e_source_mapi_folder_get_id (folder_ext) == 0;
 1792     if (is_new_source && !e_mapi_config_utils_is_online ()) {
 1793         const gchar *msg;
 1794 
 1795         switch (folder_type) {
 1796         case E_MAPI_FOLDER_TYPE_APPOINTMENT:
 1797             msg = _("Cannot create MAPI calendar in offline mode");
 1798             break;
 1799         case E_MAPI_FOLDER_TYPE_TASK:
 1800             msg = _("Cannot create MAPI task list in offline mode");
 1801             break;
 1802         case E_MAPI_FOLDER_TYPE_MEMO:
 1803             msg = _("Cannot create MAPI memo list in offline mode");
 1804             break;
 1805         case E_MAPI_FOLDER_TYPE_CONTACT:
 1806             msg = _("Cannot create MAPI address book in offline mode");
 1807             break;
 1808         /* coverity[dead_error_begin] */
 1809         default:
 1810             g_warn_if_reached ();
 1811             msg = _("Cannot create MAPI source in offline mode");
 1812             break;
 1813         }
 1814 
 1815         widget = gtk_label_new (msg);
 1816         gtk_widget_show (widget);
 1817         gtk_misc_set_alignment (GTK_MISC (widget), 0.0, 0.5);
 1818 
 1819         e_source_config_insert_widget (config, scratch_source, NULL, widget);
 1820     } else {
 1821         GtkGrid *content_grid;
 1822         GtkCellRenderer *renderer;
 1823         GtkTreeViewColumn *column;
 1824         GtkTreeStore *tree_store;
 1825         GtkWidget *tree_view, *scrolled_window;
 1826 
 1827         content_grid = GTK_GRID (gtk_grid_new ());
 1828         gtk_grid_set_row_spacing (content_grid, 2);
 1829         gtk_grid_set_column_spacing (content_grid, 6);
 1830 
 1831         widget = gtk_label_new_with_mnemonic (_("_Location:"));
 1832         gtk_misc_set_alignment (GTK_MISC (widget), 0.0, 0.5);
 1833         gtk_widget_set_hexpand (widget, TRUE);
 1834         gtk_grid_attach (content_grid, widget, 0, 0, 1, 1);
 1835 
 1836         tree_store = gtk_tree_store_new (NUM_COLS, G_TYPE_STRING, G_TYPE_UINT64, G_TYPE_POINTER);
 1837 
 1838         renderer = gtk_cell_renderer_text_new ();
 1839         column = gtk_tree_view_column_new_with_attributes ("", renderer, "text", NAME_COL, NULL);
 1840         tree_view = gtk_tree_view_new_with_model (GTK_TREE_MODEL (tree_store));
 1841         gtk_tree_view_append_column (GTK_TREE_VIEW (tree_view), column);
 1842         g_object_set (tree_view, "expander-column", column, "headers-visible", TRUE, NULL);
 1843         gtk_widget_set_sensitive (tree_view, is_new_source);
 1844         g_object_unref (tree_store);
 1845 
 1846         scrolled_window = gtk_scrolled_window_new (NULL, NULL);
 1847         gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (scrolled_window), GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC);
 1848         gtk_scrolled_window_set_shadow_type (GTK_SCROLLED_WINDOW (scrolled_window), GTK_SHADOW_IN);
 1849         g_object_set (scrolled_window, "height-request", 150, NULL);
 1850         gtk_container_add (GTK_CONTAINER (scrolled_window), tree_view);
 1851         gtk_label_set_mnemonic_widget (GTK_LABEL (widget), scrolled_window);
 1852         g_signal_connect (G_OBJECT (tree_view), "cursor-changed", G_CALLBACK (e_mapi_cursor_change), scratch_source);
 1853         gtk_widget_show_all (scrolled_window);
 1854 
 1855         gtk_grid_attach (content_grid, scrolled_window, 0, 1, 1, 1);
 1856 
 1857         if (e_mapi_config_utils_is_online ()) {
 1858             struct EMapiFolderStructureData *fsd;
 1859 
 1860             fsd = g_slice_new0 (struct EMapiFolderStructureData);
 1861             fsd->folder_type = folder_type;
 1862             fsd->folders = NULL;
 1863             fsd->tree_view = g_object_ref (tree_view);
 1864             fsd->config = g_object_ref (config);
 1865             fsd->child_source = g_object_ref (scratch_source);
 1866             fsd->registry = g_object_ref (e_source_config_get_registry (config));
 1867 
 1868             g_signal_connect_after (tree_view, "map", G_CALLBACK (tree_view_mapped_cb), NULL);
 1869             g_object_set_data_full (G_OBJECT (tree_view), "mapi-fsd-pointer", fsd, e_mapi_folder_structure_data_free);
 1870         }
 1871 
 1872         gtk_widget_set_hexpand (GTK_WIDGET (content_grid), TRUE);
 1873         gtk_widget_set_vexpand (GTK_WIDGET (content_grid), TRUE);
 1874         gtk_widget_show_all (GTK_WIDGET (content_grid));
 1875 
 1876         e_source_config_insert_widget (config, scratch_source, NULL, GTK_WIDGET (content_grid));
 1877     }
 1878 
 1879     e_source_config_add_refresh_interval (config, scratch_source);
 1880 }
 1881 
 1882 gboolean
 1883 e_mapi_config_utils_check_complete (ESource *scratch_source)
 1884 {
 1885     ESourceBackend *backend_ext = NULL;
 1886     ESourceMapiFolder *folder_ext;
 1887 
 1888     g_return_val_if_fail (scratch_source != NULL, FALSE);
 1889 
 1890     if (e_source_has_extension (scratch_source, E_SOURCE_EXTENSION_ADDRESS_BOOK)) {
 1891         backend_ext = e_source_get_extension (scratch_source, E_SOURCE_EXTENSION_ADDRESS_BOOK);
 1892     } else if (e_source_has_extension (scratch_source, E_SOURCE_EXTENSION_CALENDAR)) {
 1893         backend_ext = e_source_get_extension (scratch_source, E_SOURCE_EXTENSION_CALENDAR);
 1894     } else if (e_source_has_extension (scratch_source, E_SOURCE_EXTENSION_TASK_LIST)) {
 1895         backend_ext = e_source_get_extension (scratch_source, E_SOURCE_EXTENSION_TASK_LIST);
 1896     } else if (e_source_has_extension (scratch_source, E_SOURCE_EXTENSION_MEMO_LIST)) {
 1897         backend_ext = e_source_get_extension (scratch_source, E_SOURCE_EXTENSION_MEMO_LIST);
 1898     }
 1899 
 1900     if (!backend_ext || g_strcmp0 (e_source_backend_get_backend_name (backend_ext), "mapi") != 0)
 1901         return TRUE;
 1902 
 1903     folder_ext = e_source_get_extension (scratch_source, E_SOURCE_EXTENSION_MAPI_FOLDER);
 1904     if (!folder_ext)
 1905         return FALSE;
 1906 
 1907     if (!e_source_mapi_folder_get_id (folder_ext) &&
 1908         !e_mapi_config_utils_is_online ())
 1909         return FALSE;
 1910 
 1911     /* does not have a parent-fid which is needed for folder creation on server */
 1912     return e_source_mapi_folder_get_parent_id (folder_ext) ||
 1913         e_source_mapi_folder_get_foreign_username (folder_ext) ||
 1914         e_source_mapi_folder_is_public (folder_ext);
 1915 }