"Fossies" - the Fresh Open Source Software Archive

Member "evolution-mapi-3.46.1/src/camel/camel-mapi-store.c" (2 Dec 2022, 106716 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 "camel-mapi-store.c" see the Fossies "Dox" file reference documentation and the last Fossies "Diffs" side-by-side code changes report: 3.44.2_vs_3.45.1.

    1 /* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
    2 /*
    3  * This program is free software; you can redistribute it and/or
    4  * modify it under the terms of the GNU Lesser General Public
    5  * License as published by the Free Software Foundation; either
    6  * version 2 of the License, or (at your option) version 3.
    7  *
    8  * This program is distributed in the hope that it will be useful,
    9  * but WITHOUT ANY WARRANTY; without even the implied warranty of
   10  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
   11  * Lesser General Public License for more details.
   12  *
   13  * You should have received a copy of the GNU Lesser General Public
   14  * License along with the program; if not, see <http://www.gnu.org/licenses/>
   15  *
   16  *
   17  * Authors:
   18  *     Johnny Jacob <jjohnny@novell.com>
   19  *
   20  * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com)
   21  *
   22  */
   23 
   24 #include "evolution-mapi-config.h"
   25 
   26 #include <stdint.h>
   27 #include <stdbool.h>
   28 #include <stdlib.h>
   29 #include <stdio.h>
   30 #include <string.h>
   31 #include <ctype.h>
   32 #include <sys/types.h>
   33 #include <errno.h>
   34 
   35 #include <libmapi/libmapi.h>
   36 
   37 #include <glib/gi18n-lib.h>
   38 #include <glib/gstdio.h>
   39 
   40 #include "camel-mapi-store.h"
   41 #include "camel-mapi-folder.h"
   42 #include "camel-mapi-sasl-krb.h"
   43 #include "camel-mapi-settings.h"
   44 #include "camel-mapi-store-summary.h"
   45 #include "camel-mapi-folder-summary.h"
   46 
   47 #include <e-mapi-utils.h>
   48 #include <e-mapi-folder.h>
   49 
   50 #define d(x)
   51 
   52 struct _CamelMapiStorePrivate {
   53     EMapiConnection *connection;
   54     GRecMutex connection_lock;
   55 
   56     GHashTable *id_hash; /*get names from ids*/
   57     GHashTable *name_hash;/*get ids from names*/
   58     GHashTable *container_hash;
   59     GHashTable *parent_hash;
   60     GHashTable *default_folders; /*Default Type : Folder ID*/
   61 
   62     gboolean folders_synced; /* whether were synced folder list already */
   63 
   64     GRecMutex updates_lock;
   65     GCancellable *updates_cancellable; /* cancelled on dispose or disconnect */
   66     GSList *update_folder_names; /* gchar *foldername */
   67     guint update_folder_id;
   68     guint update_folder_list_id;
   69 };
   70 
   71 /* Forward Declarations */
   72 static void camel_subscribable_init (CamelSubscribableInterface *iface);
   73 
   74 G_DEFINE_TYPE_WITH_CODE (
   75     CamelMapiStore,
   76     camel_mapi_store,
   77     CAMEL_TYPE_OFFLINE_STORE,
   78     G_ADD_PRIVATE (CamelMapiStore)
   79     G_IMPLEMENT_INTERFACE (
   80         CAMEL_TYPE_SUBSCRIBABLE,
   81         camel_subscribable_init))
   82 
   83 /* service methods */
   84 static void mapi_store_constructed (GObject *object);
   85 static gchar    *mapi_get_name(CamelService *, gboolean );
   86 static gboolean mapi_connect_sync(CamelService *, GCancellable *cancellable, GError **);
   87 static gboolean mapi_disconnect_sync(CamelService *, gboolean , GCancellable *cancellable, GError **);
   88 static CamelAuthenticationResult mapi_authenticate_sync (CamelService *, const gchar *mechanism, GCancellable *, GError **);
   89 static GList    *mapi_query_auth_types_sync(CamelService *, GCancellable *cancellable, GError **);
   90 static void camel_mapi_store_server_notification_cb (EMapiConnection *conn, guint event_mask, gpointer event_data, gpointer user_data);
   91 
   92 /* store methods */
   93 static CamelFolderInfo * mapi_build_folder_info(CamelMapiStore *mapi_store, const gchar *parent_name, const gchar *folder_name);
   94 static gboolean mapi_fid_is_system_folder (CamelMapiStore *mapi_store, const gchar *fid);
   95 static void mapi_update_hash_table_type (CamelMapiStore *store, const gchar *full_name, guint *folder_type);
   96 
   97 static void mapi_update_folder_hash_tables (CamelMapiStore *store, const gchar *name, const gchar *fid, const gchar *parent_id);
   98 guint mapi_folders_hash_table_type_lookup (CamelMapiStore *store, const gchar *name);
   99 /* static const gchar * mapi_folders_hash_table_name_lookup (CamelMapiStore *store, const gchar *fid, gboolean use_cache); */
  100 #if 0
  101 static const gchar * mapi_folders_hash_table_fid_lookup (CamelMapiStore *store, const gchar *name, gboolean use_cache);
  102 #endif
  103 
  104 static CamelFolderInfo *
  105         mapi_store_create_folder_sync   (CamelStore *store,
  106                          const gchar *parent_name,
  107                          const gchar *folder_name,
  108                          GCancellable *cancellable,
  109                          GError **error);
  110 
  111 static gboolean
  112 cms_open_folder (CamelMapiStore *mapi_store,
  113          EMapiConnection *conn,
  114          mapi_id_t fid,
  115          mapi_object_t *obj_folder,
  116          GCancellable *cancellable,
  117          GError **perror)
  118 {
  119     CamelStoreInfo *si;
  120     CamelMapiStoreInfo *msi;
  121     GError *mapi_error = NULL;
  122     gboolean res;
  123 
  124     g_return_val_if_fail (mapi_store != NULL, FALSE);
  125     g_return_val_if_fail (mapi_store->summary != NULL, FALSE);
  126     g_return_val_if_fail (conn != NULL, FALSE);
  127     g_return_val_if_fail (fid != 0, FALSE);
  128     g_return_val_if_fail (obj_folder != NULL, FALSE);
  129 
  130     si = camel_mapi_store_summary_get_folder_id (mapi_store->summary, fid);
  131     if (!si) {
  132         g_propagate_error (perror, g_error_new_literal (CAMEL_ERROR, CAMEL_ERROR_GENERIC, _("Cannot find folder in a local cache")));
  133         return FALSE;
  134     }
  135 
  136     msi = (CamelMapiStoreInfo *) si;
  137 
  138     if ((msi->mapi_folder_flags & CAMEL_MAPI_STORE_FOLDER_FLAG_FOREIGN) != 0)
  139         res = e_mapi_connection_open_foreign_folder (conn, msi->foreign_username, fid, obj_folder, cancellable, &mapi_error);
  140     else if ((msi->mapi_folder_flags & CAMEL_MAPI_STORE_FOLDER_FLAG_PUBLIC) != 0)
  141         res = e_mapi_connection_open_public_folder (conn, fid, obj_folder, cancellable, &mapi_error);
  142     else
  143         res = e_mapi_connection_open_personal_folder (conn, fid, obj_folder, cancellable, &mapi_error);
  144 
  145     if (mapi_error) {
  146         camel_mapi_store_maybe_disconnect (mapi_store, mapi_error);
  147         g_propagate_error (perror, mapi_error);
  148     }
  149 
  150     return res;
  151 }
  152 
  153 static gboolean
  154 cms_peek_folder_store (CamelMapiStore *mapi_store,
  155                EMapiConnection *conn,
  156                mapi_id_t fid,
  157                mapi_object_t **obj_store,
  158                GCancellable *cancellable,
  159                GError **perror)
  160 {
  161     CamelStoreInfo *si;
  162     CamelMapiStoreInfo *msi;
  163     GError *mapi_error = NULL;
  164     gboolean res;
  165 
  166     g_return_val_if_fail (mapi_store != NULL, FALSE);
  167     g_return_val_if_fail (mapi_store->summary != NULL, FALSE);
  168     g_return_val_if_fail (conn != NULL, FALSE);
  169     g_return_val_if_fail (fid != 0, FALSE);
  170     g_return_val_if_fail (obj_store != NULL, FALSE);
  171 
  172     si = camel_mapi_store_summary_get_folder_id (mapi_store->summary, fid);
  173     if (!si) {
  174         g_propagate_error (perror, g_error_new_literal (CAMEL_ERROR, CAMEL_ERROR_GENERIC, _("Cannot find folder in a local cache")));
  175         return FALSE;
  176     }
  177 
  178     msi = (CamelMapiStoreInfo *) si;
  179 
  180     if ((msi->mapi_folder_flags & CAMEL_MAPI_STORE_FOLDER_FLAG_FOREIGN) != 0)
  181         res = e_mapi_connection_peek_store (conn, FALSE, msi->foreign_username, obj_store, cancellable, &mapi_error);
  182     else if ((msi->mapi_folder_flags & CAMEL_MAPI_STORE_FOLDER_FLAG_PUBLIC) != 0)
  183         res = e_mapi_connection_peek_store (conn, TRUE, NULL, obj_store, cancellable, &mapi_error);
  184     else
  185         res = e_mapi_connection_peek_store (conn, FALSE, NULL, obj_store, cancellable, &mapi_error);
  186 
  187     if (mapi_error) {
  188         camel_mapi_store_maybe_disconnect (mapi_store, mapi_error);
  189         g_propagate_error (perror, mapi_error);
  190     }
  191 
  192     return res;
  193 }
  194 
  195 static gboolean
  196 check_for_connection (CamelService *service, GError **error)
  197 {
  198     CamelMapiStore *mapi_store = CAMEL_MAPI_STORE (service);
  199     gboolean connected;
  200 
  201     if (!mapi_store)
  202         return FALSE;
  203 
  204     g_rec_mutex_lock (&mapi_store->priv->connection_lock);
  205     connected = mapi_store->priv->connection && e_mapi_connection_connected (mapi_store->priv->connection);
  206     g_rec_mutex_unlock (&mapi_store->priv->connection_lock);
  207 
  208     return connected;
  209 }
  210 
  211 /* escapes backslashes with \5C and forward slashes with \2F */
  212 static gchar *
  213 escape_slash (const gchar *str)
  214 {
  215     gint ii, jj, count = 0;
  216     gchar *res;
  217 
  218     if (!str)
  219         return NULL;
  220 
  221     for (ii = 0; str[ii]; ii++) {
  222         if (str[ii] == '\\' || str[ii] == '/')
  223             count++;
  224     }
  225 
  226     if (!count)
  227         return g_strdup (str);
  228 
  229     res = g_malloc0 (sizeof (gchar) * (1 + ii + (2 * count)));
  230     for (ii = 0, jj = 0; str[ii]; ii++, jj++) {
  231         if (str[ii] == '\\') {
  232             res[jj] = '\\';
  233             res[jj + 1] = '5';
  234             res[jj + 2] = 'C';
  235             jj += 2;
  236         } else if (str[ii] == '/') {
  237             res[jj] = '\\';
  238             res[jj + 1] = '2';
  239             res[jj + 2] = 'F';
  240             jj += 2;
  241         } else {
  242             res[jj] = str[ii];
  243         }
  244     }
  245 
  246     res[jj] = '\0';
  247 
  248     return res;
  249 }
  250 
  251 /* reverses escape_slash processing */
  252 static gchar *
  253 unescape_slash (const gchar *str)
  254 {
  255     gchar *res = g_strdup (str);
  256     gint ii, jj;
  257 
  258     for (ii = 0, jj = 0; res[ii]; ii++, jj++) {
  259         if (res[ii] == '\\' && g_ascii_isxdigit (res[ii + 1]) && g_ascii_isxdigit (res[ii + 2])) {
  260             res[jj] = ((g_ascii_xdigit_value (res[ii + 1]) & 0xF) << 4) | (g_ascii_xdigit_value (res[ii + 2]) & 0xF);
  261             ii += 2;
  262         } else if (ii != jj) {
  263             res[jj] = res[ii];
  264         }
  265     }
  266 
  267     res[jj] = '\0';
  268 
  269     return res;
  270 }
  271 
  272 static CamelFolder *
  273 mapi_get_folder_with_type (CamelStore *store, guint folder_type, GCancellable *cancellable, GError **error)
  274 {
  275     CamelMapiStore *mapi_store = CAMEL_MAPI_STORE (store);
  276     CamelFolderInfo *all_fi, *fi;
  277     CamelFolder *folder = NULL;
  278 
  279     g_return_val_if_fail (mapi_store != NULL, NULL);
  280     g_return_val_if_fail (mapi_store->priv != NULL, NULL);
  281 
  282     all_fi = camel_store_get_folder_info_sync (
  283         store, NULL, CAMEL_STORE_FOLDER_INFO_RECURSIVE,
  284         cancellable, error);
  285     if (all_fi == NULL)
  286         return NULL;
  287 
  288     fi = all_fi;
  289     while (fi) {
  290         CamelFolderInfo *next;
  291 
  292         if ((fi->flags & CAMEL_FOLDER_TYPE_MASK) == folder_type) {
  293             folder = camel_store_get_folder_sync (
  294                 store, fi->full_name, 0, cancellable, error);
  295             break;
  296         }
  297 
  298         /* move to the next, depth-first search */
  299         next = fi->child;
  300         if (!next)
  301             next = fi->next;
  302         if (!next) {
  303             next = fi->parent;
  304             while (next) {
  305                 CamelFolderInfo *sibl = next->next;
  306                 if (sibl) {
  307                     next = sibl;
  308                     break;
  309                 } else {
  310                     next = next->parent;
  311                 }
  312             }
  313         }
  314 
  315         fi = next;
  316     }
  317 
  318     camel_folder_info_free (all_fi);
  319 
  320     return folder;
  321 }
  322 
  323 static CamelFolderInfo *
  324 mapi_convert_to_folder_info (CamelMapiStore *store,
  325                              EMapiFolder *folder,
  326                              GError **error)
  327 {
  328     gchar *name;
  329     gchar *parent, *id = NULL;
  330     mapi_id_t mapi_id_folder;
  331     const gchar *par_name = NULL;
  332     CamelFolderInfo *fi;
  333 
  334     name = escape_slash (e_mapi_folder_get_name (folder));
  335 
  336     id = g_strdup_printf ("%016" G_GINT64_MODIFIER "X", e_mapi_folder_get_id (folder));
  337 
  338     fi = camel_folder_info_new ();
  339 
  340     if (folder->is_default) {
  341         switch (folder->default_type) {
  342         case olFolderTopInformationStore:
  343             fi->flags |= CAMEL_FOLDER_NOSELECT;
  344             break;
  345         case olFolderInbox:
  346             fi->flags |= CAMEL_FOLDER_TYPE_INBOX;
  347             break;
  348         case olFolderSentMail:
  349             fi->flags |= CAMEL_FOLDER_TYPE_SENT;
  350             break;
  351         case olFolderDeletedItems:
  352             fi->flags |= CAMEL_FOLDER_TYPE_TRASH;
  353             break;
  354         case olFolderOutbox:
  355             fi->flags |= CAMEL_FOLDER_TYPE_OUTBOX;
  356             break;
  357         case olFolderJunk:
  358             fi->flags |= CAMEL_FOLDER_TYPE_JUNK;
  359             break;
  360         }
  361 
  362         fi->flags |= CAMEL_FOLDER_SYSTEM;
  363     } else {
  364         switch (e_mapi_folder_get_type (folder)) {
  365         case E_MAPI_FOLDER_TYPE_CONTACT:
  366             fi->flags |= CAMEL_FOLDER_TYPE_CONTACTS;
  367             break;
  368         case E_MAPI_FOLDER_TYPE_APPOINTMENT:
  369             fi->flags |= CAMEL_FOLDER_TYPE_EVENTS;
  370             break;
  371         case E_MAPI_FOLDER_TYPE_MEMO:
  372             fi->flags |= CAMEL_FOLDER_TYPE_MEMOS;
  373             break;
  374         case E_MAPI_FOLDER_TYPE_TASK:
  375             fi->flags |= CAMEL_FOLDER_TYPE_TASKS;
  376             break;
  377         default:
  378             break;
  379         }
  380     }
  381 
  382     if (folder->child_count <= 0)
  383         fi->flags |= CAMEL_FOLDER_NOCHILDREN;
  384     /*
  385        parent_hash contains the "parent id <-> folder id" combination. So we form
  386        the path for the full name in camelfolder info by looking up the hash table until
  387        NULL is found
  388      */
  389 
  390     mapi_id_folder = e_mapi_folder_get_parent_id (folder);
  391     parent = g_strdup_printf ("%016" G_GINT64_MODIFIER "X", mapi_id_folder);
  392 
  393     fi->display_name = name;
  394 
  395     par_name = mapi_folders_hash_table_name_lookup (store, parent, TRUE);
  396     if (par_name != NULL) {
  397         gchar *str = g_strconcat (par_name, "/", name, NULL);
  398 
  399         fi->full_name = str; /* takes ownership of the string */
  400     } else {
  401         fi->full_name = g_strdup (name);
  402     }
  403 
  404     /*name_hash returns the container id given the name */
  405     mapi_update_folder_hash_tables (store, fi->full_name, id, parent);
  406 
  407     g_free (parent);
  408     g_free (id);
  409 
  410     fi->total = folder->total;
  411     fi->unread = folder->unread_count;
  412 
  413     return fi;
  414 }
  415 
  416 static void
  417 remove_path_from_store_summary (const gchar *path, gpointer value, CamelMapiStore *mstore)
  418 {
  419     const gchar *folder_id;
  420     CamelStoreInfo *si;
  421 
  422     g_return_if_fail (path != NULL);
  423     g_return_if_fail (mstore != NULL);
  424 
  425     folder_id = g_hash_table_lookup (mstore->priv->name_hash, path);
  426     if (folder_id) {
  427         /* name_hash as the second, because folder_id is from there */
  428         g_hash_table_remove (mstore->priv->id_hash, folder_id);
  429         g_hash_table_remove (mstore->priv->name_hash, path);
  430     }
  431 
  432     si = camel_store_summary_path (mstore->summary, path);
  433     if (si) {
  434         CamelFolderInfo *fi;
  435 
  436         fi = camel_folder_info_new ();
  437         fi->unread = -1;
  438         fi->total = -1;
  439         fi->display_name = g_strdup (camel_store_info_get_name (si));
  440         fi->full_name = g_strdup (camel_store_info_get_path (si));
  441         if (!fi->display_name && fi->full_name) {
  442             fi->display_name = strrchr (fi->full_name, '/');
  443             if (fi->display_name)
  444                 fi->display_name = g_strdup (fi->display_name + 1);
  445         }
  446 
  447         camel_subscribable_folder_unsubscribed (CAMEL_SUBSCRIBABLE (mstore), fi);
  448         camel_store_folder_deleted (CAMEL_STORE (mstore), fi);
  449         camel_folder_info_free (fi);
  450 
  451         camel_store_info_unref (si);
  452     }
  453 
  454     camel_store_summary_remove_path (mstore->summary, path);
  455 }
  456 
  457 static gboolean
  458 camel_mapi_update_operation_progress_cb (EMapiConnection *conn,
  459                      guint32 item_index,
  460                      guint32 items_total,
  461                      gpointer user_data,
  462                      GCancellable *cancellable,
  463                      GError **perror)
  464 {
  465     if (items_total > 0)
  466         camel_operation_progress (cancellable, 100 * item_index / items_total);
  467 
  468     return TRUE;
  469 }
  470 
  471 static gboolean
  472 mapi_folders_sync (CamelMapiStore *store, guint32 flags, GCancellable *cancellable, GError **error)
  473 {
  474     CamelMapiStorePrivate  *priv = store->priv;
  475     gboolean status;
  476     GSList *folder_list = NULL, *temp_list = NULL, *list = NULL;
  477     gboolean subscription_list = FALSE;
  478     CamelFolderInfo *info = NULL;
  479     CamelMapiStoreInfo *msi = NULL;
  480     GHashTable *old_cache_folders;
  481     GError *err = NULL;
  482     EMapiConnection *conn;
  483     GPtrArray *array;
  484     gint ii;
  485 
  486     if (!camel_mapi_store_connected (store, cancellable, NULL)) {
  487         g_set_error_literal (
  488             error, CAMEL_SERVICE_ERROR, CAMEL_SERVICE_ERROR_UNAVAILABLE,
  489             _("Folder list is not available in offline mode"));
  490         return FALSE;
  491     }
  492 
  493     conn = camel_mapi_store_ref_connection (store, cancellable, error);
  494     if (!conn)
  495         return FALSE;
  496 
  497     status = e_mapi_connection_get_folders_list (conn, &folder_list, camel_mapi_update_operation_progress_cb, NULL, cancellable, &err);
  498     if (!status) {
  499         camel_mapi_store_maybe_disconnect (store, err);
  500 
  501         g_warning ("Could not get folder list (%s)\n", err ? err->message : "Unknown error");
  502         g_clear_error (&err);
  503         g_object_unref (conn);
  504         return TRUE;
  505     }
  506 
  507     /* remember all folders in cache before update */
  508     old_cache_folders = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, NULL);
  509     array = camel_store_summary_array (store->summary);
  510     for (ii = 0; ii < array->len; ii++) {
  511         msi = g_ptr_array_index (array, ii);
  512 
  513         /* those whose left in old_cache_folders are removed at the end,
  514            which is not good for public and foreign folders, thus preserve
  515            them from an automatic removal */
  516         if (((msi->mapi_folder_flags & CAMEL_MAPI_STORE_FOLDER_FLAG_PUBLIC) == 0 &&
  517             (msi->mapi_folder_flags & CAMEL_MAPI_STORE_FOLDER_FLAG_FOREIGN) == 0) ||
  518             ((msi->mapi_folder_flags & CAMEL_MAPI_STORE_FOLDER_FLAG_PUBLIC_REAL) != 0 &&
  519             (msi->mapi_folder_flags & CAMEL_STORE_INFO_FOLDER_SUBSCRIBED) == 0))
  520             g_hash_table_insert (old_cache_folders, g_strdup (camel_store_info_get_path ((CamelStoreInfo *) msi)), GINT_TO_POINTER (1));
  521     }
  522     camel_store_summary_array_free (store->summary, array);
  523 
  524     subscription_list = (flags & CAMEL_STORE_FOLDER_INFO_SUBSCRIPTION_LIST);
  525     if (subscription_list) {
  526         GError *err = NULL;
  527 
  528         /*Consult the name <-> fid hash table for a FID.*/
  529         status = e_mapi_connection_get_pf_folders_list (conn, &folder_list, camel_mapi_update_operation_progress_cb, NULL, cancellable, &err);
  530         if (!status)
  531             g_warning ("Could not get Public folder list (%s)\n", err ? err->message : "Unknown error");
  532 
  533         camel_mapi_store_maybe_disconnect (store, err);
  534         g_clear_error (&err);
  535     }
  536 
  537     temp_list = folder_list;
  538     list = folder_list;
  539 
  540     /*populate the hash table for finding the mapping from container id <-> folder name*/
  541     for (;temp_list != NULL; temp_list = g_slist_next (temp_list) ) {
  542         const gchar *full_name = NULL;
  543         gchar *fid = NULL, *parent_id = NULL, *tmp = NULL;
  544         guint *folder_type = g_new0 (guint, 1);
  545 
  546         fid = g_strdup_printf ("%016" G_GINT64_MODIFIER "X", e_mapi_folder_get_id ((EMapiFolder *)(temp_list->data)));
  547         parent_id = g_strdup_printf ("%016" G_GINT64_MODIFIER "X", e_mapi_folder_get_parent_id ((EMapiFolder *)(temp_list->data)));
  548         full_name = g_hash_table_lookup (priv->id_hash, fid);
  549         if (!full_name) {
  550             const gchar *par_full_name;
  551 
  552             par_full_name = g_hash_table_lookup (priv->id_hash, parent_id);
  553             if (par_full_name) {
  554                 gchar *escaped = escape_slash (e_mapi_folder_get_name (temp_list->data));
  555                 tmp = g_strconcat (par_full_name, "/", escaped, NULL);
  556                 full_name = tmp;
  557                 g_free (escaped);
  558             } else {
  559                 tmp = escape_slash (e_mapi_folder_get_name (temp_list->data));
  560                 full_name = tmp;
  561             }
  562         } else {
  563             /* known full_name - everything is escaped already */
  564             tmp = g_strdup (full_name);
  565             full_name = tmp;
  566         }
  567 
  568         /* remove from here; what lefts is not on the server any more */
  569         g_hash_table_remove (old_cache_folders, full_name);
  570         *folder_type = ((EMapiFolder *)(temp_list->data))->container_class;
  571         mapi_update_folder_hash_tables (store, full_name, fid, parent_id);
  572         mapi_update_hash_table_type (store, full_name, folder_type);
  573         if (((EMapiFolder *)(temp_list->data))->is_default) {
  574             guint *type = g_new0 (guint, 1);
  575             *type = ((EMapiFolder *)(temp_list->data))->default_type;
  576             g_hash_table_insert (priv->default_folders, type,
  577                          g_strdup(fid));
  578         }
  579         g_free (fid);
  580         g_free (parent_id);
  581         g_free (tmp);
  582     }
  583 
  584     for (;folder_list != NULL; folder_list = g_slist_next (folder_list)) {
  585         EMapiFolder *folder = (EMapiFolder *) folder_list->data;
  586 
  587         if (folder->default_type == olPublicFoldersAllPublicFolders)
  588             continue;
  589 
  590         if (folder->container_class == E_MAPI_FOLDER_TYPE_MAIL) {
  591             info = mapi_convert_to_folder_info (store, folder, NULL);
  592             msi = (CamelMapiStoreInfo *) camel_store_summary_path (store->summary, info->full_name);
  593 
  594             if (!msi) {
  595                 msi = (CamelMapiStoreInfo *) camel_mapi_store_summary_add_from_full (store->summary,
  596                         info->full_name,
  597                         e_mapi_folder_get_id (folder),
  598                         e_mapi_folder_get_parent_id (folder),
  599                         info->flags,
  600                         folder->category == E_MAPI_FOLDER_CATEGORY_PERSONAL ? CAMEL_MAPI_STORE_FOLDER_FLAG_PERSONAL :
  601                         (CAMEL_MAPI_STORE_FOLDER_FLAG_PUBLIC | CAMEL_MAPI_STORE_FOLDER_FLAG_PUBLIC_REAL),
  602                         NULL);
  603                 if (msi == NULL)
  604                     continue;
  605 
  606                 camel_store_info_ref ((CamelStoreInfo *) msi);
  607 
  608                 if (!subscription_list) {
  609                     camel_store_folder_created (CAMEL_STORE (store), info);
  610                     camel_subscribable_folder_subscribed (CAMEL_SUBSCRIBABLE (store), info);
  611                 }
  612             } else if (e_mapi_folder_get_id (folder) != msi->folder_id ||
  613                    e_mapi_folder_get_parent_id (folder) != msi->parent_id) {
  614                 msi->folder_id = e_mapi_folder_get_id (folder);
  615                 msi->parent_id = e_mapi_folder_get_parent_id (folder);
  616             }
  617 
  618             msi->info.flags = info->flags;
  619             msi->info.total = info->total;
  620             msi->info.unread = info->unread;
  621             msi->mapi_folder_flags |= CAMEL_MAPI_STORE_FOLDER_FLAG_MAIL;
  622 
  623             camel_store_info_unref ((CamelStoreInfo *) msi);
  624             camel_folder_info_free (info);
  625         } else if (folder->category == E_MAPI_FOLDER_CATEGORY_PUBLIC) {
  626             info = mapi_convert_to_folder_info (store, folder, NULL);
  627             msi = (CamelMapiStoreInfo *) camel_store_summary_path (store->summary, info->full_name);
  628 
  629             if (!msi) {
  630                 msi = (CamelMapiStoreInfo *) camel_mapi_store_summary_add_from_full (store->summary,
  631                         info->full_name,
  632                         e_mapi_folder_get_id (folder),
  633                         e_mapi_folder_get_parent_id (folder),
  634                         info->flags,
  635                         CAMEL_MAPI_STORE_FOLDER_FLAG_PUBLIC | CAMEL_MAPI_STORE_FOLDER_FLAG_PUBLIC_REAL,
  636                         NULL);
  637 
  638                 if (msi)
  639                     camel_store_info_ref ((CamelStoreInfo *) msi);
  640             } else if (e_mapi_folder_get_id (folder) != msi->folder_id ||
  641                    e_mapi_folder_get_parent_id (folder) != msi->parent_id) {
  642                 msi->folder_id = e_mapi_folder_get_id (folder);
  643                 msi->parent_id = e_mapi_folder_get_parent_id (folder);
  644             }
  645 
  646             if (msi == NULL)
  647                 continue;
  648 
  649             msi->info.flags = info->flags;
  650 
  651             camel_store_info_unref ((CamelStoreInfo *) msi);
  652             camel_folder_info_free (info);
  653         }
  654     }
  655 
  656     /* Weed out deleted folders */
  657     g_hash_table_foreach (old_cache_folders, (GHFunc) remove_path_from_store_summary, store);
  658     g_hash_table_destroy (old_cache_folders);
  659 
  660     camel_store_summary_touch (store->summary);
  661     camel_store_summary_save (store->summary);
  662 
  663     g_slist_foreach (list, (GFunc) e_mapi_folder_free, NULL);
  664     g_slist_free (list);
  665 
  666     priv->folders_synced = TRUE;
  667     g_object_unref (conn);
  668 
  669     return TRUE;
  670 }
  671 
  672 static gchar *
  673 mapi_concat (const gchar *prefix, const gchar *suffix)
  674 {
  675     gsize len;
  676 
  677     len = strlen (prefix);
  678     if (len == 0 || prefix[len - 1] == '/')
  679         return g_strdup_printf ("%s%s", prefix, suffix);
  680     else
  681         return g_strdup_printf ("%s%c%s", prefix, '/', suffix);
  682 }
  683 
  684 static gint
  685 match_path (const gchar *path, const gchar *name)
  686 {
  687     gchar p, n;
  688 
  689     p = *path++;
  690     n = *name++;
  691     while (n && p) {
  692         if (n == p) {
  693             p = *path++;
  694             n = *name++;
  695         } else if (p == '%') {
  696             if (n != '/') {
  697                 n = *name++;
  698             } else {
  699                 p = *path++;
  700             }
  701         } else if (p == '*') {
  702             return TRUE;
  703         } else
  704             return FALSE;
  705     }
  706 
  707     return n == 0 && (p == '%' || p == 0);
  708 }
  709 
  710 static void
  711 unescape_folder_names (CamelFolderInfo *fi)
  712 {
  713     while (fi) {
  714         if (fi->display_name && strchr (fi->display_name, '\\')) {
  715             gchar *unescaped;
  716 
  717             unescaped = unescape_slash (fi->display_name);
  718             g_free (fi->display_name);
  719             fi->display_name = unescaped;
  720         }
  721 
  722         if (fi->child)
  723             unescape_folder_names (fi->child);
  724 
  725         fi = fi->next;
  726     }
  727 }
  728 
  729 static CamelFolderInfo *
  730 mapi_get_folder_info_offline (CamelStore *store,
  731                   const gchar *top,
  732                   guint32 flags,
  733                   GCancellable *cancellable,
  734                   GError **error)
  735 {
  736     CamelMapiStore *mapi_store = CAMEL_MAPI_STORE (store);
  737     CamelSettings *settings;
  738     CamelMapiSettings *mapi_settings;
  739     CamelFolderInfo *fi;
  740     CamelSession *session = NULL;
  741     GList *my_sources = NULL;
  742     GPtrArray *folders;
  743     GPtrArray *array;
  744     gchar *path;
  745     gboolean subscribed, subscription_list = FALSE;
  746     gboolean has_public_folders = FALSE, has_foreign_folders = FALSE;
  747     gchar *profile;
  748     guint ii;
  749 
  750     subscription_list = (flags & CAMEL_STORE_FOLDER_INFO_SUBSCRIPTION_LIST);
  751     subscribed = (flags & CAMEL_STORE_FOLDER_INFO_SUBSCRIBED);
  752 
  753     settings = camel_service_ref_settings (CAMEL_SERVICE (store));
  754 
  755     mapi_settings = CAMEL_MAPI_SETTINGS (settings);
  756     profile = camel_mapi_settings_dup_profile (mapi_settings);
  757 
  758     g_object_unref (settings);
  759 
  760     folders = g_ptr_array_new ();
  761 
  762     if (subscription_list) {
  763         session = camel_service_ref_session (CAMEL_SERVICE (store));
  764         if (session) {
  765             ESourceRegistry *registry;
  766             GList *all_sources;
  767 
  768             registry = e_source_registry_new_sync (NULL, NULL);
  769             all_sources = e_source_registry_list_sources (registry, NULL);
  770 
  771             my_sources = e_mapi_utils_filter_sources_for_profile (all_sources, profile);
  772 
  773             g_list_free_full (all_sources, g_object_unref);
  774             g_clear_object (&registry);
  775         }
  776     }
  777 
  778     if (!top || !*top)
  779         top = "";
  780 
  781     path = mapi_concat (top, "*");
  782 
  783     array = camel_store_summary_array (mapi_store->summary);
  784 
  785     for (ii = 0; ii < array->len; ii++) {
  786         CamelStoreInfo *si;
  787         CamelMapiStoreInfo *msi;
  788 
  789         si = g_ptr_array_index (array, ii);
  790         msi = (CamelMapiStoreInfo *) si;
  791 
  792         /* Allow only All Public Folders hierarchy;
  793            Subscribed public folders are those in Favorites/... - skip them too */
  794         if (subscription_list &&
  795             ((msi->mapi_folder_flags & CAMEL_MAPI_STORE_FOLDER_FLAG_PUBLIC) == 0 ||
  796             (msi->mapi_folder_flags & CAMEL_MAPI_STORE_FOLDER_FLAG_PUBLIC_REAL) == 0 ||
  797             (msi->mapi_folder_flags & CAMEL_MAPI_STORE_FOLDER_FLAG_FOREIGN) != 0)) {
  798             continue;
  799         }
  800 
  801         /* Allow Mailbox and Favourites (Subscribed public folders) */
  802         if (subscribed &&
  803             (((si->flags & CAMEL_STORE_INFO_FOLDER_SUBSCRIBED) == 0 &&
  804              (msi->mapi_folder_flags & CAMEL_MAPI_STORE_FOLDER_FLAG_PERSONAL) == 0) ||
  805             (!subscription_list && (msi->mapi_folder_flags & CAMEL_MAPI_STORE_FOLDER_FLAG_PUBLIC_REAL) != 0))) {
  806             continue;
  807         }
  808 
  809         if (!subscription_list &&
  810             (msi->mapi_folder_flags & CAMEL_MAPI_STORE_FOLDER_FLAG_MAIL) == 0 &&
  811             (si->flags & CAMEL_STORE_INFO_FOLDER_SUBSCRIBED) != 0 &&
  812             ((msi->mapi_folder_flags & CAMEL_MAPI_STORE_FOLDER_FLAG_PUBLIC) != 0 ||
  813              (msi->mapi_folder_flags & CAMEL_MAPI_STORE_FOLDER_FLAG_FOREIGN) != 0)) {
  814             continue;
  815         }
  816 
  817         if (strcmp (top, camel_store_info_get_path (si)) == 0
  818              || match_path (path, camel_store_info_get_path (si))) {
  819             const gchar *store_info_path = camel_store_info_get_path (si);
  820 
  821             has_public_folders = has_public_folders || (msi->mapi_folder_flags & CAMEL_MAPI_STORE_FOLDER_FLAG_PUBLIC) != 0;
  822             has_foreign_folders = has_foreign_folders || (msi->mapi_folder_flags & CAMEL_MAPI_STORE_FOLDER_FLAG_FOREIGN) != 0;
  823 
  824             fi = mapi_build_folder_info (mapi_store, NULL, store_info_path);
  825             fi->unread = si->unread;
  826             fi->total = si->total;
  827             fi->flags = si->flags;
  828 
  829             if (subscription_list) {
  830                 guint folder_type;
  831                 CamelStoreInfo *si2;
  832 
  833                 si2 = camel_mapi_store_summary_get_folder_id (mapi_store->summary, msi->folder_id);
  834                 if (si2) {
  835                     if (si != si2)
  836                         fi->flags = si2->flags;
  837 
  838                     camel_store_info_unref (si2);
  839                 }
  840 
  841                 folder_type = mapi_folders_hash_table_type_lookup (mapi_store, camel_store_info_get_path (si));
  842                 if (folder_type != E_MAPI_FOLDER_TYPE_UNKNOWN && folder_type != E_MAPI_FOLDER_TYPE_MAIL) {
  843                     if (e_mapi_folder_is_subscribed_as_esource (my_sources, profile, msi->folder_id))
  844                         fi->flags |= CAMEL_FOLDER_SUBSCRIBED;
  845                 }
  846             }
  847 
  848             g_ptr_array_add (folders, fi);
  849         }
  850     }
  851 
  852     camel_store_summary_array_free (mapi_store->summary, array);
  853 
  854     if (!subscription_list && !*top) {
  855         if (has_public_folders) {
  856             fi = mapi_build_folder_info (mapi_store, NULL, DISPLAY_NAME_FAVORITES);
  857             fi->flags |= CAMEL_FOLDER_NOSELECT | CAMEL_FOLDER_SYSTEM;
  858 
  859             g_ptr_array_add (folders, fi);
  860         }
  861 
  862         if (has_foreign_folders) {
  863             fi = mapi_build_folder_info (mapi_store, NULL, DISPLAY_NAME_FOREIGN_FOLDERS);
  864             fi->flags |= CAMEL_FOLDER_NOSELECT | CAMEL_FOLDER_SYSTEM;
  865 
  866             g_ptr_array_add (folders, fi);
  867         }
  868     }
  869 
  870     g_free (path);
  871     /* this adds also fake folders, if missing */
  872     fi = camel_folder_info_build (folders, top, '/', TRUE);
  873     g_ptr_array_free (folders, TRUE);
  874 
  875     unescape_folder_names (fi);
  876 
  877     if (!fi && error && !*error)
  878         g_set_error_literal (error, CAMEL_STORE_ERROR, CAMEL_STORE_ERROR_NO_FOLDER,
  879             (flags & CAMEL_STORE_FOLDER_INFO_SUBSCRIPTION_LIST) != 0 ?
  880             _("No public folder found") : _("No folder found"));
  881 
  882     g_list_free_full (my_sources, g_object_unref);
  883     g_clear_object (&session);
  884 
  885     g_free (profile);
  886 
  887     return fi;
  888 }
  889 
  890 static gboolean
  891 mapi_forget_folder (CamelMapiStore *mapi_store, const gchar *folder_name, GError **error)
  892 {
  893     CamelService *service;
  894     const gchar *user_cache_dir;
  895     gchar *state_file;
  896     gchar *folder_dir, *storage_path;
  897     CamelFolderInfo *fi;
  898 
  899     service = CAMEL_SERVICE (mapi_store);
  900     user_cache_dir = camel_service_get_user_cache_dir (service);
  901 
  902     storage_path = g_build_filename (user_cache_dir, "folders", NULL);
  903 
  904     folder_dir = g_build_filename (storage_path, folder_name, NULL);
  905     g_free (storage_path);
  906 
  907     if (g_access (folder_dir, F_OK) == 0) {
  908         state_file = g_build_filename (folder_dir, "cmeta", NULL);
  909         g_unlink (state_file);
  910         g_free (state_file);
  911 
  912         g_rmdir (folder_dir);
  913         g_free (folder_dir);
  914     }
  915 
  916     camel_store_summary_remove_path (mapi_store->summary, folder_name);
  917     camel_store_summary_save (mapi_store->summary);
  918 
  919     fi = mapi_build_folder_info (mapi_store, NULL, folder_name);
  920     camel_store_folder_deleted (CAMEL_STORE (mapi_store), fi);
  921     camel_folder_info_free (fi);
  922 
  923     return TRUE;
  924 }
  925 
  926 static void
  927 mapi_rename_folder_infos (CamelMapiStore *mapi_store, const gchar *old_name, const gchar *new_name)
  928 {
  929     gint olen;
  930     CamelStoreInfo *si = NULL;
  931     GPtrArray *array;
  932     guint ii;
  933 
  934     g_return_if_fail (mapi_store != NULL);
  935     g_return_if_fail (old_name != NULL);
  936     g_return_if_fail (new_name != NULL);
  937 
  938     olen = strlen (old_name);
  939 
  940     array = camel_store_summary_array (mapi_store->summary);
  941 
  942     for (ii = 0; ii < array->len; ii++) {
  943         const gchar *full_name;
  944 
  945         si = g_ptr_array_index (array, ii);
  946 
  947         full_name = camel_store_info_get_path (si);
  948         if (full_name && g_str_has_prefix (full_name, old_name) && !g_str_equal (full_name, old_name) &&
  949             full_name [olen] == '/' && full_name [olen + 1] != '\0') {
  950             /* it's a subfolder of old_name */
  951             mapi_id_t fid = ((CamelMapiStoreInfo *)si)->folder_id;
  952 
  953             if (fid) {
  954                 gchar *new_full_name;
  955                 gchar *fid_str = e_mapi_util_mapi_id_to_string (fid);
  956 
  957                 /* do not remove it from name_hash yet, because this function
  958                    will be called for it again */
  959                 /* g_hash_table_remove (mapi_store->priv->name_hash, full_name); */
  960                 g_hash_table_remove (mapi_store->priv->id_hash, fid_str);
  961 
  962                 /* parent is still the same, only the path changed */
  963                 new_full_name = g_strconcat (new_name, full_name + olen + (g_str_has_suffix (new_name, "/") ? 1 : 0), NULL);
  964 
  965                 mapi_update_folder_hash_tables (mapi_store, new_full_name, fid_str, NULL);
  966 
  967                 camel_store_info_set_value (si, CAMEL_STORE_INFO_PATH, new_full_name);
  968                 camel_store_summary_touch (mapi_store->summary);
  969 
  970                 g_free (new_full_name);
  971                 g_free (fid_str);
  972             }
  973         }
  974     }
  975 
  976     camel_store_summary_array_free (mapi_store->summary, array);
  977 }
  978 
  979 static void
  980 stop_pending_updates (CamelMapiStore *mapi_store)
  981 {
  982     CamelMapiStorePrivate *priv;
  983 
  984     g_return_if_fail (mapi_store != NULL);
  985     g_return_if_fail (mapi_store->priv != NULL);
  986 
  987     priv = mapi_store->priv;
  988 
  989     g_rec_mutex_lock (&priv->updates_lock);
  990     if (priv->updates_cancellable) {
  991         g_cancellable_cancel (priv->updates_cancellable);
  992         g_object_unref (priv->updates_cancellable);
  993         priv->updates_cancellable = NULL;
  994     }
  995 
  996     if (priv->update_folder_names) {
  997         g_slist_free_full (priv->update_folder_names, g_free);
  998         priv->update_folder_names = NULL;
  999     }
 1000 
 1001     if (priv->update_folder_id) {
 1002         g_source_remove (priv->update_folder_id);
 1003         priv->update_folder_id = 0;
 1004     }
 1005 
 1006     if (priv->update_folder_list_id) {
 1007         g_source_remove (priv->update_folder_list_id);
 1008         priv->update_folder_list_id = 0;
 1009     }
 1010 
 1011     g_rec_mutex_unlock (&priv->updates_lock);
 1012 }
 1013 
 1014 static void
 1015 mapi_store_dispose (GObject *object)
 1016 {
 1017     CamelMapiStore *mapi_store;
 1018     CamelMapiStorePrivate *priv;
 1019 
 1020     mapi_store = CAMEL_MAPI_STORE (object);
 1021     priv = mapi_store->priv;
 1022 
 1023     stop_pending_updates (CAMEL_MAPI_STORE (object));
 1024 
 1025     if (mapi_store->summary) {
 1026         camel_store_summary_save (mapi_store->summary);
 1027         g_object_unref (mapi_store->summary);
 1028         mapi_store->summary = NULL;
 1029     }
 1030 
 1031     g_rec_mutex_lock (&mapi_store->priv->connection_lock);
 1032     if (priv->connection != NULL) {
 1033         g_signal_handlers_disconnect_by_func (priv->connection, camel_mapi_store_server_notification_cb, object);
 1034 
 1035         g_object_unref (priv->connection);
 1036         priv->connection = NULL;
 1037     }
 1038     g_rec_mutex_unlock (&mapi_store->priv->connection_lock);
 1039 
 1040     /* Chain up to parent's dispose() method. */
 1041     G_OBJECT_CLASS (camel_mapi_store_parent_class)->dispose (object);
 1042 }
 1043 
 1044 static void
 1045 mapi_store_finalize (GObject *object)
 1046 {
 1047     CamelMapiStore *mapi_store = CAMEL_MAPI_STORE (object);
 1048 
 1049     g_clear_pointer (&mapi_store->priv->id_hash, g_hash_table_destroy);
 1050     g_clear_pointer (&mapi_store->priv->name_hash, g_hash_table_destroy);
 1051     g_clear_pointer (&mapi_store->priv->parent_hash, g_hash_table_destroy);
 1052     g_clear_pointer (&mapi_store->priv->default_folders, g_hash_table_destroy);
 1053     g_clear_pointer (&mapi_store->priv->container_hash, g_hash_table_destroy);
 1054 
 1055     g_rec_mutex_clear (&mapi_store->priv->connection_lock);
 1056     g_rec_mutex_clear (&mapi_store->priv->updates_lock);
 1057 
 1058     /* Chain up to parent's finalize() method. */
 1059     G_OBJECT_CLASS (camel_mapi_store_parent_class)->finalize (object);
 1060 }
 1061 
 1062 static gboolean
 1063 mapi_store_can_refresh_folder (CamelStore *store,
 1064                                CamelFolderInfo *info,
 1065                                GError **error)
 1066 {
 1067     CamelService *service;
 1068     CamelSettings *settings;
 1069     CamelMapiSettings *mapi_settings;
 1070     gboolean check_all;
 1071 
 1072     /* skip unselectable folders from automatic refresh */
 1073     if (info && (info->flags & CAMEL_FOLDER_NOSELECT) != 0)
 1074         return FALSE;
 1075 
 1076     service = CAMEL_SERVICE (store);
 1077 
 1078     settings = camel_service_ref_settings (service);
 1079 
 1080     mapi_settings = CAMEL_MAPI_SETTINGS (settings);
 1081     check_all = camel_mapi_settings_get_check_all (mapi_settings);
 1082 
 1083     g_object_unref (settings);
 1084 
 1085     if (check_all)
 1086         return TRUE;
 1087 
 1088     return CAMEL_STORE_CLASS(camel_mapi_store_parent_class)->can_refresh_folder (store, info, error);
 1089 }
 1090 
 1091 static gchar *
 1092 mapi_build_folder_dir (const gchar *user_cache_dir,
 1093                const gchar *folder_name)
 1094 {
 1095     GString *path;
 1096     gchar **elems;
 1097     gint ii;
 1098 
 1099     g_return_val_if_fail (user_cache_dir != NULL, NULL);
 1100     g_return_val_if_fail (*user_cache_dir != 0, NULL);
 1101     g_return_val_if_fail (folder_name != NULL, NULL);
 1102 
 1103     elems = g_strsplit (folder_name, "/", -1);
 1104     g_return_val_if_fail (elems != NULL, NULL);
 1105 
 1106     path = g_string_new (user_cache_dir);
 1107     if (path->str[path->len - 1] != G_DIR_SEPARATOR)
 1108         g_string_append_c (path, G_DIR_SEPARATOR);
 1109     g_string_append (path, "folders");
 1110 
 1111     for (ii = 0; elems[ii]; ii++) {
 1112         if (path->str[path->len - 1] != G_DIR_SEPARATOR)
 1113             g_string_append_c (path, G_DIR_SEPARATOR);
 1114 
 1115         if (ii != 0) {
 1116             g_string_append (path, "sub");
 1117             g_string_append_c (path, G_DIR_SEPARATOR);
 1118         }
 1119 
 1120         if (elems[ii + 1])
 1121             g_string_append (path, elems[ii]);
 1122     }
 1123 
 1124     g_strfreev (elems);
 1125 
 1126     return g_string_free (path, FALSE);
 1127 }
 1128 
 1129 static CamelFolder *
 1130 mapi_store_get_folder_sync (CamelStore *store,
 1131                             const gchar *folder_name,
 1132                             guint32 flags,
 1133                             GCancellable *cancellable,
 1134                             GError **error)
 1135 {
 1136     CamelMapiStore *mapi_store = CAMEL_MAPI_STORE (store);
 1137     CamelService *service;
 1138     CamelStoreInfo *si;
 1139     CamelFolder *folder;
 1140     const gchar *user_cache_dir;
 1141     gchar *folder_dir;
 1142 
 1143     si = camel_store_summary_path (mapi_store->summary, folder_name);
 1144     if (si)
 1145         camel_store_info_unref (si);
 1146 
 1147     service = CAMEL_SERVICE (store);
 1148     user_cache_dir = camel_service_get_user_cache_dir (service);
 1149 
 1150     folder_dir = mapi_build_folder_dir (user_cache_dir, folder_name);
 1151     g_return_val_if_fail (folder_dir != NULL, NULL);
 1152 
 1153     folder = camel_mapi_folder_new (store, folder_name, folder_dir, flags, error);
 1154     g_free (folder_dir);
 1155 
 1156     return folder;
 1157 }
 1158 
 1159 static CamelFolderInfo*
 1160 mapi_store_get_folder_info_sync (CamelStore *store,
 1161                                  const gchar *top,
 1162                                  guint32 flags,
 1163                                  GCancellable *cancellable,
 1164                                  GError **error)
 1165 {
 1166     CamelMapiStore *mapi_store = CAMEL_MAPI_STORE (store);
 1167     CamelService *service;
 1168 
 1169     if (!camel_offline_store_get_online (CAMEL_OFFLINE_STORE (store)) &&
 1170         (flags & CAMEL_STORE_FOLDER_INFO_SUBSCRIPTION_LIST) != 0) {
 1171         g_set_error_literal (
 1172             error, CAMEL_SERVICE_ERROR, CAMEL_SERVICE_ERROR_UNAVAILABLE,
 1173             _("Folder list is not available in offline mode"));
 1174         return NULL;
 1175     }
 1176 
 1177     service = CAMEL_SERVICE (store);
 1178 
 1179     if (camel_offline_store_get_online (CAMEL_OFFLINE_STORE (store))) {
 1180         CamelServiceConnectionStatus status;
 1181 
 1182         status = camel_service_get_connection_status (service);
 1183 
 1184         /* update folders from the server only when asking for the top most or the 'top' is not known;
 1185            otherwise believe the local cache, because folders sync is pretty slow operation to be done
 1186            one every single question on the folder info */
 1187         if ((flags & CAMEL_STORE_FOLDER_INFO_SUBSCRIPTION_LIST) != 0 ||
 1188             (!(flags & CAMEL_STORE_FOLDER_INFO_SUBSCRIBED)) ||
 1189             (top && *top && !camel_mapi_store_folder_id_lookup (mapi_store, top)) ||
 1190             camel_store_summary_count (mapi_store->summary) <= 1 ||
 1191             !mapi_store->priv->folders_synced) {
 1192             if (status == CAMEL_SERVICE_DISCONNECTED) {
 1193                 gchar *name = camel_service_get_name (service, TRUE);
 1194 
 1195                 camel_operation_push_message (cancellable, _("Connecting to “%s”"), name);
 1196                 camel_service_connect_sync (service, cancellable, NULL);
 1197                 camel_operation_pop_message (cancellable);
 1198 
 1199                 g_free (name);
 1200             }
 1201 
 1202             if (check_for_connection (service, NULL) || status == CAMEL_SERVICE_CONNECTING) {
 1203                 gboolean first_check = !mapi_store->priv->folders_synced;
 1204 
 1205                 if (!mapi_folders_sync (mapi_store, flags, cancellable, error))
 1206                     return NULL;
 1207 
 1208                 if (first_check) {
 1209                     camel_store_summary_touch (mapi_store->summary);
 1210                     camel_store_summary_save (mapi_store->summary);
 1211                 }
 1212             }
 1213         }
 1214     }
 1215 
 1216     return mapi_get_folder_info_offline (store, top, flags, cancellable, error);
 1217 }
 1218 
 1219 static CamelFolder *
 1220 mapi_store_get_junk_folder_sync (CamelStore *store,
 1221                                  GCancellable *cancellable,
 1222                                  GError **error)
 1223 {
 1224     return mapi_get_folder_with_type (store, CAMEL_FOLDER_TYPE_JUNK, cancellable, error);
 1225 }
 1226 
 1227 static CamelFolder *
 1228 mapi_store_get_trash_folder_sync (CamelStore *store,
 1229                                   GCancellable *cancellable,
 1230                                   GError **error)
 1231 {
 1232     return mapi_get_folder_with_type (store, CAMEL_FOLDER_TYPE_TRASH, cancellable, error);
 1233 }
 1234 
 1235 static CamelFolderInfo *
 1236 mapi_store_create_folder_sync (CamelStore *store,
 1237                                const gchar *parent_name,
 1238                                const gchar *folder_name,
 1239                                GCancellable *cancellable,
 1240                                GError **error)
 1241 {
 1242     CamelMapiStore *mapi_store = CAMEL_MAPI_STORE (store);
 1243     CamelMapiStorePrivate  *priv = mapi_store->priv;
 1244     CamelFolderInfo *root = NULL;
 1245     gchar *parent_id;
 1246     mapi_id_t parent_fid, new_folder_id;
 1247     mapi_object_t obj_folder;
 1248     EMapiConnection *conn;
 1249     GError *mapi_error = NULL;
 1250 
 1251     if (!camel_offline_store_get_online (CAMEL_OFFLINE_STORE (store))) {
 1252         g_set_error_literal (
 1253             error, CAMEL_SERVICE_ERROR, CAMEL_SERVICE_ERROR_UNAVAILABLE,
 1254             _("Cannot create MAPI folders in offline mode"));
 1255         return NULL;
 1256     }
 1257 
 1258     if (mapi_fid_is_system_folder (mapi_store, camel_mapi_store_folder_id_lookup (mapi_store, folder_name))) {
 1259         g_set_error (
 1260             error, CAMEL_ERROR, CAMEL_ERROR_GENERIC,
 1261             _("Cannot create new folder “%s”"),
 1262             folder_name);
 1263         return NULL;
 1264     }
 1265 
 1266     if (!mapi_connect_sync (CAMEL_SERVICE(store), cancellable, NULL)) {
 1267         g_set_error (
 1268             error, CAMEL_SERVICE_ERROR,
 1269             CAMEL_SERVICE_ERROR_CANT_AUTHENTICATE,
 1270             _("Authentication failed"));
 1271         return NULL;
 1272     }
 1273 
 1274     if (parent_name && (!*parent_name ||
 1275         g_str_equal (parent_name, DISPLAY_NAME_FAVORITES) ||
 1276         g_str_equal (parent_name, DISPLAY_NAME_FOREIGN_FOLDERS))) {
 1277         g_set_error_literal (
 1278             error, CAMEL_SERVICE_ERROR,
 1279             CAMEL_SERVICE_ERROR_UNAVAILABLE,
 1280             _("MAPI folders can be created only within mailbox of the logged in user"));
 1281         return NULL;
 1282     }
 1283 
 1284     if (parent_name && *parent_name)
 1285         parent_id = g_strdup (g_hash_table_lookup (priv->name_hash, parent_name));
 1286     else
 1287         parent_id = NULL;
 1288 
 1289     if (!parent_id) {
 1290         g_set_error (
 1291             error, CAMEL_SERVICE_ERROR,
 1292             CAMEL_SERVICE_ERROR_UNAVAILABLE,
 1293             _("Cannot find folder “%s”"), parent_name ? parent_name : "");
 1294         return NULL;
 1295     }
 1296     e_mapi_util_mapi_id_from_string (parent_id, &parent_fid);
 1297     new_folder_id = 0;
 1298 
 1299     conn = camel_mapi_store_ref_connection (mapi_store, cancellable, error);
 1300     if (!conn)
 1301         return NULL;
 1302 
 1303     if (!cms_open_folder (mapi_store, conn, parent_fid, &obj_folder, cancellable, error)) {
 1304         g_object_unref (conn);
 1305         return NULL;
 1306     }
 1307 
 1308     if (!e_mapi_connection_create_folder (conn, &obj_folder, folder_name, IPF_NOTE, &new_folder_id, cancellable, &mapi_error))
 1309         new_folder_id = 0;
 1310     e_mapi_connection_close_folder (conn, &obj_folder, cancellable, &mapi_error);
 1311 
 1312     if (new_folder_id != 0) {
 1313         gchar *folder_id_str;
 1314         CamelMapiStoreInfo *parent_msi;
 1315         gboolean is_public, is_foreign;
 1316 
 1317         parent_msi = (CamelMapiStoreInfo *) camel_mapi_store_summary_get_folder_id (mapi_store->summary, parent_fid);
 1318         is_public = parent_msi && (parent_msi->mapi_folder_flags & CAMEL_MAPI_STORE_FOLDER_FLAG_PUBLIC) != 0;
 1319         is_foreign = parent_msi && (parent_msi->mapi_folder_flags & CAMEL_MAPI_STORE_FOLDER_FLAG_FOREIGN) != 0;
 1320 
 1321         root = mapi_build_folder_info (mapi_store, parent_name, folder_name);
 1322         camel_mapi_store_summary_add_from_full (mapi_store->summary,
 1323             root->full_name,
 1324             new_folder_id,
 1325             parent_fid,
 1326             root->flags | ((is_public || is_foreign) ? CAMEL_FOLDER_SUBSCRIBED | CAMEL_STORE_INFO_FOLDER_SUBSCRIBED : 0),
 1327             (is_public ? CAMEL_MAPI_STORE_FOLDER_FLAG_PUBLIC :
 1328             is_foreign ? CAMEL_MAPI_STORE_FOLDER_FLAG_FOREIGN :
 1329             CAMEL_MAPI_STORE_FOLDER_FLAG_PERSONAL) | CAMEL_MAPI_STORE_FOLDER_FLAG_MAIL,
 1330             is_foreign ? parent_msi->foreign_username : NULL);
 1331 
 1332         if (parent_msi)
 1333             camel_store_info_unref ((CamelStoreInfo *) parent_msi);
 1334 
 1335         camel_store_summary_save (mapi_store->summary);
 1336 
 1337         folder_id_str = e_mapi_util_mapi_id_to_string (new_folder_id);
 1338         mapi_update_folder_hash_tables (mapi_store, root->full_name, folder_id_str, parent_id);
 1339         g_free (folder_id_str);
 1340 
 1341         camel_store_folder_created (store, root);
 1342         camel_subscribable_folder_subscribed (CAMEL_SUBSCRIBABLE (store), root);
 1343     } else {
 1344         if (mapi_error) {
 1345             if (!e_mapi_utils_propagate_cancelled_error (mapi_error, error))
 1346                 g_set_error (
 1347                     error, CAMEL_ERROR, CAMEL_ERROR_GENERIC,
 1348                     _("Cannot create folder “%s”: %s"), folder_name, mapi_error->message);
 1349             camel_mapi_store_maybe_disconnect (mapi_store, mapi_error);
 1350             g_error_free (mapi_error);
 1351         } else {
 1352             g_set_error (
 1353                 error, CAMEL_ERROR, CAMEL_ERROR_GENERIC,
 1354                 _("Cannot create folder “%s”"), folder_name);
 1355         }
 1356     }
 1357 
 1358     g_object_unref (conn);
 1359 
 1360     return root;
 1361 
 1362 }
 1363 
 1364 static gboolean
 1365 mapi_store_delete_folder_sync (CamelStore *store,
 1366                                const gchar *folder_name,
 1367                                GCancellable *cancellable,
 1368                                GError **error)
 1369 {
 1370     CamelMapiStore *mapi_store = CAMEL_MAPI_STORE (store);
 1371     CamelMapiStorePrivate  *priv = mapi_store->priv;
 1372     CamelMapiStoreInfo *msi;
 1373     EMapiConnection *conn;
 1374     mapi_object_t *obj_store = NULL;
 1375     const gchar *folder_id;
 1376     mapi_id_t folder_fid;
 1377     gboolean status = FALSE;
 1378     gboolean success = TRUE;
 1379     GError *local_error = NULL;
 1380 
 1381     if (!camel_offline_store_get_online (CAMEL_OFFLINE_STORE (store))) {
 1382         g_set_error_literal (
 1383             error, CAMEL_SERVICE_ERROR, CAMEL_SERVICE_ERROR_UNAVAILABLE,
 1384             _("Cannot delete MAPI folders in offline mode"));
 1385         return FALSE;
 1386     }
 1387 
 1388     if (!camel_mapi_store_connected ((CamelMapiStore *)store, cancellable, &local_error)) {
 1389         if (local_error != NULL) {
 1390             g_propagate_error (error, local_error);
 1391             return FALSE;
 1392         }
 1393 
 1394         g_set_error_literal (
 1395             error, CAMEL_SERVICE_ERROR, CAMEL_SERVICE_ERROR_UNAVAILABLE,
 1396             _("Cannot delete MAPI folders in offline mode"));
 1397 
 1398         return FALSE;
 1399     }
 1400 
 1401     folder_id = g_hash_table_lookup (priv->name_hash, folder_name);
 1402     if (!folder_id) {
 1403         g_set_error (
 1404             error, CAMEL_SERVICE_ERROR,
 1405             CAMEL_SERVICE_ERROR_UNAVAILABLE,
 1406             _("Cannot find folder “%s”"), folder_name);
 1407         return FALSE;
 1408     }
 1409 
 1410     e_mapi_util_mapi_id_from_string (folder_id, &folder_fid);
 1411 
 1412     conn = camel_mapi_store_ref_connection (mapi_store, cancellable, error);
 1413     if (!conn)
 1414         return FALSE;
 1415 
 1416     msi = (CamelMapiStoreInfo *) camel_mapi_store_summary_get_folder_id (mapi_store->summary, folder_fid);
 1417     if (!msi ||
 1418         (msi->mapi_folder_flags & CAMEL_MAPI_STORE_FOLDER_FLAG_PUBLIC) != 0 ||
 1419         (msi->mapi_folder_flags & CAMEL_MAPI_STORE_FOLDER_FLAG_FOREIGN) != 0) {
 1420         /* do not remove foreign or public folders, just unsubscribe from them,
 1421            even when there are folder delete permissons on the folder
 1422         */
 1423         status = TRUE;
 1424     } else if (cms_peek_folder_store (mapi_store, conn, folder_fid, &obj_store, cancellable, &local_error))
 1425         status = e_mapi_connection_remove_folder (conn, obj_store, folder_fid, cancellable, &local_error);
 1426     else
 1427         status = FALSE;
 1428 
 1429     g_object_unref (conn);
 1430 
 1431     if (status) {
 1432         success = mapi_forget_folder (mapi_store, folder_name, &local_error);
 1433 
 1434         if (success) {
 1435             /* remove from name_cache at the end, because the folder_id is from there */
 1436             /*g_hash_table_remove (priv->parent_hash, folder_id);*/
 1437             g_hash_table_remove (priv->id_hash, folder_id);
 1438             g_hash_table_remove (priv->name_hash, folder_name);
 1439         }
 1440 
 1441         if (local_error) {
 1442             camel_mapi_store_maybe_disconnect (mapi_store, local_error);
 1443             g_propagate_error (error, local_error);
 1444         }
 1445     } else {
 1446         success = FALSE;
 1447 
 1448         if (local_error) {
 1449             if (!e_mapi_utils_propagate_cancelled_error (local_error, error))
 1450                 g_set_error (
 1451                     error, CAMEL_ERROR, CAMEL_ERROR_GENERIC,
 1452                     _("Cannot remove folder “%s”: %s"),
 1453                     folder_name, local_error->message);
 1454 
 1455             camel_mapi_store_maybe_disconnect (mapi_store, local_error);
 1456             g_error_free (local_error);
 1457         } else {
 1458             g_set_error (
 1459                 error, CAMEL_ERROR, CAMEL_ERROR_GENERIC,
 1460                 _("Cannot remove folder “%s”"),
 1461                 folder_name);
 1462         }
 1463     }
 1464 
 1465     return success;
 1466 }
 1467 
 1468 static gboolean
 1469 mapi_store_rename_folder_sync (CamelStore *store,
 1470                                const gchar *old_name,
 1471                                const gchar *new_name,
 1472                                GCancellable *cancellable,
 1473                                GError **error)
 1474 {
 1475     CamelMapiStore *mapi_store = CAMEL_MAPI_STORE (store);
 1476     CamelMapiStorePrivate  *priv = mapi_store->priv;
 1477     EMapiConnection *conn;
 1478     CamelStoreInfo *si = NULL;
 1479     CamelService *service;
 1480     const gchar *user_cache_dir;
 1481     gchar *old_parent, *new_parent, *tmp;
 1482     gboolean move_cache = TRUE;
 1483     const gchar *old_fid_str, *new_parent_fid_str = NULL;
 1484     mapi_id_t old_fid;
 1485     GError *local_error = NULL;
 1486 
 1487     if (!camel_offline_store_get_online (CAMEL_OFFLINE_STORE (store))) {
 1488         g_set_error_literal (
 1489             error, CAMEL_SERVICE_ERROR, CAMEL_SERVICE_ERROR_UNAVAILABLE,
 1490             _("Cannot rename MAPI folders in offline mode"));
 1491         return FALSE;
 1492     }
 1493 
 1494     service = CAMEL_SERVICE (store);
 1495     user_cache_dir = camel_service_get_user_cache_dir (service);
 1496 
 1497     if (!camel_mapi_store_connected ((CamelMapiStore *)store, cancellable, &local_error)) {
 1498         if (local_error != NULL) {
 1499             g_propagate_error (error, local_error);
 1500             return FALSE;
 1501         }
 1502 
 1503         g_set_error_literal (
 1504             error, CAMEL_SERVICE_ERROR, CAMEL_SERVICE_ERROR_UNAVAILABLE,
 1505             _("Cannot rename MAPI folders in offline mode"));
 1506 
 1507         return FALSE;
 1508     }
 1509 
 1510     /* Need a full name of a folder */
 1511     old_fid_str = camel_mapi_store_folder_id_lookup (mapi_store, old_name);
 1512     if (!old_fid_str) {
 1513         g_set_error (
 1514             error, CAMEL_ERROR, CAMEL_ERROR_GENERIC,
 1515             /* Translators: “%s” is current name of the folder */
 1516             _("Cannot rename MAPI folder “%s”. Folder does not exist"),
 1517             old_name);
 1518         return FALSE;
 1519     }
 1520 
 1521     /*Do not allow rename for system folders.*/
 1522     if (mapi_fid_is_system_folder (mapi_store, old_fid_str)) {
 1523         g_set_error (
 1524             error, CAMEL_ERROR, CAMEL_ERROR_GENERIC,
 1525             /* Translators: “%s to %s” is current name of the folder  and
 1526                new name of the folder.*/
 1527             _("Cannot rename MAPI default folder “%s” to “%s”"),
 1528             old_name, new_name);
 1529         return FALSE;
 1530     }
 1531 
 1532     old_parent = g_strdup (old_name);
 1533     tmp = strrchr (old_parent, '/');
 1534     if (tmp) {
 1535         *tmp = '\0';
 1536     } else {
 1537         strcpy (old_parent, "");
 1538     }
 1539 
 1540     new_parent = g_strdup (new_name);
 1541     tmp = strrchr (new_parent, '/');
 1542     if (tmp) {
 1543         *tmp = '\0';
 1544         tmp++; /* here's a new folder name now */
 1545     } else {
 1546         strcpy (new_parent, "");
 1547         tmp = NULL;
 1548     }
 1549 
 1550     if (!e_mapi_util_mapi_id_from_string (old_fid_str, &old_fid)) {
 1551         g_set_error (
 1552             error, CAMEL_ERROR, CAMEL_ERROR_GENERIC,
 1553             _("Cannot rename MAPI folder “%s” to “%s”"),
 1554             old_name, new_name);
 1555         g_free (old_parent);
 1556         g_free (new_parent);
 1557         return FALSE;
 1558     }
 1559 
 1560     conn = camel_mapi_store_ref_connection (mapi_store, cancellable, error);
 1561     if (!conn) {
 1562         g_free (old_parent);
 1563         g_free (new_parent);
 1564 
 1565         return FALSE;
 1566     }
 1567 
 1568     if (tmp == NULL || g_str_equal (old_parent, new_parent)) {
 1569         gchar *folder_id;
 1570         gboolean status = FALSE;
 1571         mapi_object_t obj_folder;
 1572 
 1573         if (cms_open_folder (mapi_store, conn, old_fid, &obj_folder, cancellable, &local_error)) {
 1574             status = e_mapi_connection_rename_folder (conn, &obj_folder, tmp ? tmp : new_name, cancellable, &local_error);
 1575             e_mapi_connection_close_folder (conn, &obj_folder, cancellable, &local_error);
 1576         }
 1577 
 1578         /* renaming in the same folder, thus no MoveFolder necessary */
 1579         if (!status) {
 1580             g_object_unref (conn);
 1581 
 1582             if (local_error) {
 1583                 if (!e_mapi_utils_propagate_cancelled_error (local_error, error))
 1584                     g_set_error (
 1585                         error, CAMEL_ERROR, CAMEL_ERROR_GENERIC,
 1586                         /* Translators: “%s to %s” is current name of the folder and new name of the folder.
 1587                            The last “%s” is a detailed error message. */
 1588                         _("Cannot rename MAPI folder “%s” to “%s”: %s"),
 1589                         old_name, new_name, local_error->message);
 1590                 camel_mapi_store_maybe_disconnect (mapi_store, local_error);
 1591                 g_error_free (local_error);
 1592             } else {
 1593                 g_set_error (
 1594                     error, CAMEL_ERROR, CAMEL_ERROR_GENERIC,
 1595                     /* Translators: “%s to %s” is current name of the folder and new name of the folder. */
 1596                     _("Cannot rename MAPI folder “%s” to “%s”"),
 1597                     old_name, new_name);
 1598             }
 1599 
 1600             g_free (old_parent);
 1601             g_free (new_parent);
 1602             return FALSE;
 1603         }
 1604 
 1605         mapi_rename_folder_infos (mapi_store, old_name, new_name);
 1606 
 1607         folder_id = g_strdup (old_fid_str);
 1608 
 1609         /* this frees old_fid_str */
 1610         g_hash_table_remove (priv->name_hash, old_name);
 1611         g_hash_table_remove (priv->id_hash, folder_id);
 1612 
 1613         mapi_update_folder_hash_tables (mapi_store, new_name, folder_id, NULL);
 1614 
 1615         g_free (folder_id);
 1616     } else {
 1617         const gchar *old_parent_fid_str;
 1618         mapi_id_t old_parent_fid, new_parent_fid;
 1619         gchar *folder_id;
 1620 
 1621         old_parent_fid_str = camel_mapi_store_folder_id_lookup (mapi_store, old_parent);
 1622         new_parent_fid_str = camel_mapi_store_folder_id_lookup (mapi_store, new_parent);
 1623         if (!old_parent_fid_str && new_parent_fid_str) {
 1624             CamelStoreInfo *new_si;
 1625 
 1626             /* Folder was in a store-summary, and is known, but the parent gone.
 1627                The reason might be that this is a subfolder whose parent got moved
 1628                a second ago. Thus just update local summary with proper paths. */
 1629             move_cache = FALSE;
 1630 
 1631             new_si = camel_store_summary_path (mapi_store->summary, new_name);
 1632             if (new_si) {
 1633                 si = camel_store_summary_path (mapi_store->summary, old_name);
 1634                 if (si) {
 1635                     /* for cases where folder sync realized new folders before this got updated;
 1636                        this shouldn't duplicate the info in summary, but remove the old one */
 1637                     camel_store_summary_remove (mapi_store->summary, si);
 1638                     si = NULL;
 1639                 }
 1640                 camel_store_info_unref (new_si);
 1641             }
 1642         } else {
 1643             gboolean status = FALSE;
 1644 
 1645             if (old_parent_fid_str && new_parent_fid_str &&
 1646                e_mapi_util_mapi_id_from_string (old_parent_fid_str, &old_parent_fid) &&
 1647                e_mapi_util_mapi_id_from_string (new_parent_fid_str, &new_parent_fid)) {
 1648                 mapi_object_t src_obj_folder, src_parent_obj_folder, des_obj_folder;
 1649 
 1650                 if (cms_open_folder (mapi_store, conn, old_fid, &src_obj_folder, cancellable, &local_error)) {
 1651                     if (cms_open_folder (mapi_store, conn, old_parent_fid, &src_parent_obj_folder, cancellable, &local_error)) {
 1652                         if (cms_open_folder (mapi_store, conn, new_parent_fid, &des_obj_folder, cancellable, &local_error)) {
 1653                             status = e_mapi_connection_move_folder (conn, &src_obj_folder, &src_parent_obj_folder, &des_obj_folder, tmp, cancellable, &local_error);
 1654                             e_mapi_connection_close_folder (conn, &des_obj_folder, cancellable, &local_error);
 1655                         }
 1656                         e_mapi_connection_close_folder (conn, &src_parent_obj_folder, cancellable, &local_error);
 1657                     }
 1658                     e_mapi_connection_close_folder (conn, &src_obj_folder, cancellable, &local_error);
 1659                 }
 1660             }
 1661 
 1662             if (!status) {
 1663                 g_object_unref (conn);
 1664 
 1665                 if (local_error) {
 1666                     if (!e_mapi_utils_propagate_cancelled_error (local_error, error))
 1667                         g_set_error (
 1668                             error, CAMEL_ERROR, CAMEL_ERROR_GENERIC,
 1669                             _("Cannot rename MAPI folder “%s” to “%s”: %s"),
 1670                             old_name, new_name, local_error->message);
 1671                     camel_mapi_store_maybe_disconnect (mapi_store, local_error);
 1672                     g_error_free (local_error);
 1673                 } else {
 1674                     g_set_error (
 1675                         error, CAMEL_ERROR, CAMEL_ERROR_GENERIC,
 1676                         _("Cannot rename MAPI folder “%s” to “%s”"),
 1677                         old_name, new_name);
 1678                 }
 1679                 g_free (old_parent);
 1680                 g_free (new_parent);
 1681                 return FALSE;
 1682             } else {
 1683                 /* folder was moved, update all subfolders immediately, thus
 1684                    the next get_folder_info call will know about them */
 1685                 mapi_rename_folder_infos (mapi_store, old_name, new_name);
 1686             }
 1687         }
 1688 
 1689         folder_id = g_strdup (old_fid_str);
 1690 
 1691         /* this frees old_fid_str */
 1692         g_hash_table_remove (priv->name_hash, old_name);
 1693         g_hash_table_remove (priv->id_hash, folder_id);
 1694         /*g_hash_table_remove (priv->parent_hash, folder_id);*/
 1695 
 1696         mapi_update_folder_hash_tables (mapi_store, new_name, folder_id, new_parent_fid_str);
 1697 
 1698         g_free (folder_id);
 1699     }
 1700 
 1701     g_object_unref (conn);
 1702 
 1703     si = camel_store_summary_path (mapi_store->summary, old_name);
 1704     if (si) {
 1705         mapi_id_t new_parent_fid;
 1706 
 1707         camel_store_info_set_value (si, CAMEL_STORE_INFO_PATH, new_name);
 1708         if (new_parent_fid_str && e_mapi_util_mapi_id_from_string (new_parent_fid_str, &new_parent_fid))
 1709             ((CamelMapiStoreInfo *) si)->parent_id = new_parent_fid;
 1710         camel_store_info_unref (si);
 1711         camel_store_summary_touch (mapi_store->summary);
 1712     }
 1713 
 1714     if (move_cache) {
 1715         gchar *oldpath, *newpath;
 1716 
 1717         oldpath = g_build_filename (user_cache_dir, "folders", old_name, NULL);
 1718         newpath = g_build_filename (user_cache_dir, "folders", new_name, NULL);
 1719 
 1720         if (g_file_test (oldpath, G_FILE_TEST_IS_DIR) && g_rename (oldpath, newpath) == -1 && errno != ENOENT) {
 1721             g_warning ("Could not rename message cache '%s' to '%s': %s: cache reset", oldpath, newpath, g_strerror (errno));
 1722         }
 1723 
 1724         g_free (oldpath);
 1725         g_free (newpath);
 1726     }
 1727 
 1728     g_free (old_parent);
 1729     g_free (new_parent);
 1730 
 1731     return TRUE;
 1732 }
 1733 
 1734 static gboolean
 1735 mapi_store_folder_is_subscribed (CamelSubscribable *subscribable,
 1736                                  const gchar *folder_name)
 1737 {
 1738     CamelMapiStore *mapi_store = CAMEL_MAPI_STORE (subscribable);
 1739     CamelStoreInfo *si;
 1740     gint truth = FALSE;
 1741 
 1742     if ((si = camel_store_summary_path (mapi_store->summary, folder_name))) {
 1743         truth = (si->flags & CAMEL_STORE_INFO_FOLDER_SUBSCRIBED) != 0;
 1744         camel_store_info_unref (si);
 1745     }
 1746 
 1747     return truth;
 1748 }
 1749 
 1750 static gboolean
 1751 mapi_store_subscribe_folder_sync (CamelSubscribable *subscribable,
 1752                                   const gchar *folder_name,
 1753                                   GCancellable *cancellable,
 1754                                   GError **error)
 1755 {
 1756     CamelMapiStore *mapi_store = CAMEL_MAPI_STORE (subscribable);
 1757     CamelFolderInfo *fi;
 1758     CamelStoreInfo *si, *si2;
 1759     CamelMapiStoreInfo *msi;
 1760     const gchar *use_folder_name = folder_name, *f_name;
 1761     gchar *path;
 1762 
 1763     if (!camel_offline_store_get_online (CAMEL_OFFLINE_STORE (mapi_store))) {
 1764         g_set_error_literal (
 1765             error, CAMEL_SERVICE_ERROR, CAMEL_SERVICE_ERROR_UNAVAILABLE,
 1766             _("Cannot subscribe MAPI folders in offline mode"));
 1767         return FALSE;
 1768     }
 1769 
 1770     /* subscribe is done only with public folders, which are added to Favorites */
 1771     f_name = strrchr (folder_name, '/');
 1772     if (!f_name) {
 1773         /* Don't process All Public Folder. */
 1774         return TRUE;
 1775     }
 1776 
 1777     use_folder_name = f_name + 1;
 1778 
 1779     si = camel_store_summary_path (mapi_store->summary, folder_name);
 1780     if (!si) {
 1781         g_set_error (
 1782             error, CAMEL_ERROR, CAMEL_ERROR_GENERIC,
 1783             _("Folder “%s” not found"), folder_name);
 1784 
 1785         return FALSE;
 1786     }
 1787 
 1788     msi = (CamelMapiStoreInfo *) si;
 1789     if ((msi->mapi_folder_flags & CAMEL_MAPI_STORE_FOLDER_FLAG_PUBLIC) == 0) {
 1790         /* this is not a public folder, but MAPI supports subscribtions
 1791            only on public folders, thus report success
 1792         */
 1793 
 1794         camel_store_info_unref (si);
 1795 
 1796         return TRUE;
 1797     }
 1798 
 1799     path = g_strconcat (DISPLAY_NAME_FAVORITES, "/", use_folder_name, NULL);
 1800     si2 = camel_store_summary_path (mapi_store->summary, path);
 1801     if (si2 && ((CamelMapiStoreInfo *) si2)->folder_id == msi->folder_id && (si2->flags & CAMEL_FOLDER_SUBSCRIBED) != 0) {
 1802         /* already subscribed */
 1803         camel_store_info_unref (si);
 1804         camel_store_info_unref (si2);
 1805 
 1806         return TRUE;
 1807     } else if (si2) {
 1808         camel_store_info_unref (si2);
 1809         si2 = NULL;
 1810     }
 1811 
 1812     if ((msi->mapi_folder_flags & CAMEL_MAPI_STORE_FOLDER_FLAG_MAIL) != 0) {
 1813         /* make sure parent folder is known */
 1814         fi = mapi_build_folder_info (mapi_store, NULL, DISPLAY_NAME_FAVORITES);
 1815         fi->flags |= CAMEL_FOLDER_NOSELECT | CAMEL_FOLDER_SYSTEM;
 1816 
 1817         camel_subscribable_folder_subscribed (CAMEL_SUBSCRIBABLE (mapi_store), fi);
 1818 
 1819         camel_folder_info_free (fi);
 1820 
 1821         camel_mapi_store_ensure_unique_path (mapi_store, &path);
 1822 
 1823         /* then add copy with Favorites/xxx */
 1824         si2 = camel_mapi_store_summary_add_from_full (mapi_store->summary,
 1825             path,
 1826             msi->folder_id,
 1827             msi->parent_id,
 1828             msi->camel_folder_flags | CAMEL_FOLDER_SUBSCRIBED | CAMEL_STORE_INFO_FOLDER_SUBSCRIBED | CAMEL_FOLDER_NOCHILDREN,
 1829             msi->mapi_folder_flags & ~(CAMEL_MAPI_STORE_FOLDER_FLAG_PUBLIC_REAL),
 1830             msi->foreign_username);
 1831 
 1832         if (si2) {
 1833             camel_store_summary_touch (mapi_store->summary);
 1834 
 1835             fi = mapi_build_folder_info (mapi_store, NULL, path);
 1836             fi->unread = si2->unread;
 1837             fi->total = si2->total;
 1838             fi->flags = si2->flags;
 1839             camel_subscribable_folder_subscribed (subscribable, fi);
 1840             camel_folder_info_free (fi);
 1841         } else {
 1842             g_debug ("%s: Failed to add '%s' to store's summary", G_STRFUNC, path);
 1843         }
 1844     } else {
 1845         CamelSettings *settings;
 1846         CamelMapiSettings *mapi_settings;
 1847         guint folder_type = mapi_folders_hash_table_type_lookup (mapi_store, folder_name);
 1848         gchar *profile;
 1849 
 1850         /* remember the folder, thus it can be removed and checked in Subscriptions dialog */
 1851         msi->camel_folder_flags = msi->camel_folder_flags | CAMEL_FOLDER_SUBSCRIBED | CAMEL_STORE_INFO_FOLDER_SUBSCRIBED | CAMEL_FOLDER_NOCHILDREN;
 1852         camel_store_summary_touch (mapi_store->summary);
 1853 
 1854         settings = camel_service_ref_settings (CAMEL_SERVICE (mapi_store));
 1855         mapi_settings = CAMEL_MAPI_SETTINGS (settings);
 1856         profile = camel_mapi_settings_dup_profile (mapi_settings);
 1857 
 1858         g_object_unref (settings);
 1859 
 1860         if (!e_mapi_folder_add_as_esource (NULL, folder_type, profile,
 1861             TRUE /* camel_offline_settings_get_stay_synchronized (CAMEL_OFFLINE_SETTINGS (mapi_settings)) */,
 1862             E_MAPI_FOLDER_CATEGORY_PUBLIC,
 1863             NULL,
 1864             use_folder_name,
 1865             msi->folder_id,
 1866             (gint) msi->folder_id,
 1867             cancellable,
 1868             error)) {
 1869             camel_store_info_unref (si);
 1870             g_free (profile);
 1871             g_free (path);
 1872 
 1873             return FALSE;
 1874         }
 1875 
 1876         g_free (profile);
 1877     }
 1878     camel_store_info_unref (si);
 1879     camel_store_summary_save (mapi_store->summary);
 1880 
 1881     g_free (path);
 1882 
 1883     return TRUE;
 1884 }
 1885 
 1886 static gboolean
 1887 mapi_store_unsubscribe_subfolders (CamelMapiStore *mapi_store,
 1888                    mapi_id_t parent_id,
 1889                    GCancellable *cancellable,
 1890                    GError **error);
 1891 
 1892 static gboolean
 1893 mapi_store_unsubscribe_folder_internal_sync (CamelSubscribable *subscribable,
 1894                          const gchar *folder_name,
 1895                          gboolean check_foreign_subfolders,
 1896                          GCancellable *cancellable,
 1897                          GError **error)
 1898 {
 1899     gboolean res = TRUE;
 1900     CamelFolderInfo *fi;
 1901     CamelStoreInfo *si;
 1902     CamelMapiStoreInfo *msi;
 1903     CamelMapiStore *mapi_store = CAMEL_MAPI_STORE (subscribable);
 1904 
 1905     if (!camel_offline_store_get_online (CAMEL_OFFLINE_STORE (mapi_store))) {
 1906         g_set_error_literal (
 1907             error, CAMEL_SERVICE_ERROR, CAMEL_SERVICE_ERROR_UNAVAILABLE,
 1908             _("Cannot unsubscribe MAPI folders in offline mode"));
 1909         return FALSE;
 1910     }
 1911 
 1912     si = camel_store_summary_path (mapi_store->summary, folder_name);
 1913     if (!si) {
 1914         /* no such folder in the cache, might be unsubscribed already */
 1915         return TRUE;
 1916     }
 1917 
 1918     msi = (CamelMapiStoreInfo *) si;
 1919     if ((msi->mapi_folder_flags & CAMEL_MAPI_STORE_FOLDER_FLAG_MAIL) != 0) {
 1920         CamelStoreInfo *si2 = camel_mapi_store_summary_get_folder_id (mapi_store->summary, msi->folder_id);
 1921 
 1922         if (si2) {
 1923             CamelMapiStoreInfo *msi2 = (CamelMapiStoreInfo *) si2;
 1924 
 1925             fi = mapi_build_folder_info (mapi_store, NULL, camel_store_info_get_path (si2));
 1926             camel_subscribable_folder_unsubscribed (subscribable, fi);
 1927             camel_folder_info_free (fi);
 1928 
 1929             if (((msi2->mapi_folder_flags & CAMEL_MAPI_STORE_FOLDER_FLAG_PUBLIC) != 0 &&
 1930                 (msi2->mapi_folder_flags & CAMEL_MAPI_STORE_FOLDER_FLAG_PUBLIC_REAL) == 0) ||
 1931                 (msi2->mapi_folder_flags & CAMEL_MAPI_STORE_FOLDER_FLAG_FOREIGN) != 0) {
 1932                 if (check_foreign_subfolders &&
 1933                     (msi2->mapi_folder_flags & CAMEL_MAPI_STORE_FOLDER_FLAG_FOREIGN) != 0 &&
 1934                     (msi2->mapi_folder_flags & CAMEL_MAPI_STORE_FOLDER_FLAG_FOREIGN_WITH_SUBFOLDERS) != 0) {
 1935                     res = mapi_store_unsubscribe_subfolders (mapi_store, msi2->folder_id, cancellable, error);
 1936                 }
 1937 
 1938                 if (res) {
 1939                     res = mapi_forget_folder (mapi_store, folder_name, error);
 1940 
 1941                     /* remove calls also free on 'si2' */
 1942                     camel_store_summary_remove (mapi_store->summary, si2);
 1943                     camel_store_summary_touch (mapi_store->summary);
 1944                 } else {
 1945                     camel_store_info_unref (si2);
 1946                 }
 1947             } else {
 1948                 camel_store_info_unref (si2);
 1949             }
 1950         } else {
 1951             g_debug ("%s: Failed to find subscribed by folder ID", G_STRFUNC);
 1952         }
 1953     } else {
 1954         CamelSettings *settings;
 1955         const gchar *profile;
 1956 
 1957         settings = camel_service_ref_settings (CAMEL_SERVICE (mapi_store));
 1958         profile = camel_mapi_settings_get_profile (CAMEL_MAPI_SETTINGS (settings));
 1959 
 1960         res = e_mapi_folder_remove_as_esource (NULL,
 1961             profile,
 1962             msi->folder_id,
 1963             cancellable,
 1964             error);
 1965 
 1966         g_object_unref (settings);
 1967     }
 1968 
 1969     if (res && (((msi->mapi_folder_flags & CAMEL_MAPI_STORE_FOLDER_FLAG_PUBLIC) != 0 &&
 1970         (msi->mapi_folder_flags & CAMEL_MAPI_STORE_FOLDER_FLAG_PUBLIC_REAL) == 0) ||
 1971         (msi->mapi_folder_flags & CAMEL_MAPI_STORE_FOLDER_FLAG_FOREIGN) != 0)) {
 1972         if (check_foreign_subfolders &&
 1973             (msi->mapi_folder_flags & CAMEL_MAPI_STORE_FOLDER_FLAG_FOREIGN) != 0 &&
 1974             (msi->mapi_folder_flags & CAMEL_MAPI_STORE_FOLDER_FLAG_FOREIGN_WITH_SUBFOLDERS) != 0) {
 1975             res = mapi_store_unsubscribe_subfolders (mapi_store, msi->folder_id, cancellable, error);
 1976         }
 1977 
 1978         if (res) {
 1979             /* remove calls also free on 'si' */
 1980             camel_store_summary_remove (mapi_store->summary, si);
 1981             camel_store_summary_touch (mapi_store->summary);
 1982         } else {
 1983             camel_store_info_unref (si);
 1984         }
 1985     } else {
 1986         camel_store_info_unref (si);
 1987     }
 1988 
 1989     camel_store_summary_save (mapi_store->summary);
 1990 
 1991     return res;
 1992 }
 1993 
 1994 static gboolean
 1995 mapi_store_unsubscribe_folder_sync (CamelSubscribable *subscribable,
 1996                                     const gchar *folder_name,
 1997                                     GCancellable *cancellable,
 1998                                     GError **error)
 1999 {
 2000     return mapi_store_unsubscribe_folder_internal_sync (subscribable, folder_name, TRUE, cancellable, error);
 2001 }
 2002 
 2003 /* This can be particularly slow (with many folders) */
 2004 static GSList * /* (transfer container) (element-type CamelMapiStoreInfo *) */
 2005 mapi_store_gather_subfolders (GPtrArray *array, /* CamelMapiStoreInfo * */
 2006                   mapi_id_t parent_id)
 2007 {
 2008     GSList *subfolders = NULL;
 2009     guint ii;
 2010 
 2011     if (!array)
 2012         return NULL;
 2013 
 2014     for (ii = 0; ii < array->len; ii++) {
 2015         CamelMapiStoreInfo *msi = g_ptr_array_index (array, ii);
 2016 
 2017         if (msi && msi->parent_id == parent_id) {
 2018             GSList *subsub;
 2019 
 2020             subfolders = g_slist_prepend (subfolders, msi);
 2021 
 2022             subsub = mapi_store_gather_subfolders (array, msi->folder_id);
 2023             if (subsub)
 2024                 subfolders = g_slist_concat (subfolders, subsub);
 2025         }
 2026     }
 2027 
 2028     return subfolders;
 2029 }
 2030 
 2031 static gboolean
 2032 mapi_store_unsubscribe_subfolders (CamelMapiStore *mapi_store,
 2033                    mapi_id_t parent_id,
 2034                    GCancellable *cancellable,
 2035                    GError **error)
 2036 {
 2037     GPtrArray *array;
 2038     GSList *subfolders, *link;
 2039     gboolean res = TRUE;
 2040 
 2041     array = camel_store_summary_array (mapi_store->summary);
 2042     subfolders = mapi_store_gather_subfolders (array, parent_id);
 2043 
 2044     for (link = subfolders; link && res; link = g_slist_next (link)) {
 2045         CamelMapiStoreInfo *msi = link->data;
 2046 
 2047         if (!msi || !(msi->mapi_folder_flags & CAMEL_MAPI_STORE_FOLDER_FLAG_FOREIGN))
 2048             continue;
 2049 
 2050         res = mapi_store_unsubscribe_folder_internal_sync (CAMEL_SUBSCRIBABLE (mapi_store),
 2051             camel_store_info_get_path ((CamelStoreInfo *) msi),
 2052             FALSE, cancellable, error);
 2053     }
 2054 
 2055     camel_store_summary_array_free (mapi_store->summary, array);
 2056     g_slist_free (subfolders);
 2057 
 2058     return res;
 2059 }
 2060 
 2061 static void
 2062 mapi_migrate_to_user_cache_dir (CamelService *service)
 2063 {
 2064     const gchar *user_data_dir, *user_cache_dir;
 2065 
 2066     g_return_if_fail (service != NULL);
 2067     g_return_if_fail (CAMEL_IS_SERVICE (service));
 2068 
 2069     user_data_dir = camel_service_get_user_data_dir (service);
 2070     user_cache_dir = camel_service_get_user_cache_dir (service);
 2071 
 2072     g_return_if_fail (user_data_dir != NULL);
 2073     g_return_if_fail (user_cache_dir != NULL);
 2074 
 2075     /* migrate only if the source directory exists and the destination doesn't */
 2076     if (g_file_test (user_data_dir, G_FILE_TEST_EXISTS | G_FILE_TEST_IS_DIR) &&
 2077         !g_file_test (user_cache_dir, G_FILE_TEST_EXISTS | G_FILE_TEST_IS_DIR)) {
 2078         gchar *parent_dir;
 2079 
 2080         parent_dir = g_path_get_dirname (user_cache_dir);
 2081         g_mkdir_with_parents (parent_dir, S_IRWXU);
 2082         g_free (parent_dir);
 2083 
 2084         if (g_rename (user_data_dir, user_cache_dir) == -1)
 2085             g_debug ("%s: Failed to migrate '%s' to '%s': %s", G_STRFUNC, user_data_dir, user_cache_dir, g_strerror (errno));
 2086     }
 2087 }
 2088 
 2089 static void
 2090 camel_mapi_store_class_init (CamelMapiStoreClass *class)
 2091 {
 2092     GObjectClass *object_class;
 2093     CamelServiceClass *service_class;
 2094     CamelStoreClass *store_class;
 2095 
 2096     /* register MAPIKRB auth type */
 2097     CAMEL_TYPE_MAPI_SASL_KRB;
 2098 
 2099     object_class = G_OBJECT_CLASS (class);
 2100     object_class->dispose = mapi_store_dispose;
 2101     object_class->finalize = mapi_store_finalize;
 2102     object_class->constructed = mapi_store_constructed;
 2103 
 2104     service_class = CAMEL_SERVICE_CLASS (class);
 2105     service_class->settings_type = CAMEL_TYPE_MAPI_SETTINGS;
 2106     service_class->get_name = mapi_get_name;
 2107     service_class->connect_sync = mapi_connect_sync;
 2108     service_class->disconnect_sync = mapi_disconnect_sync;
 2109     service_class->authenticate_sync = mapi_authenticate_sync;
 2110     service_class->query_auth_types_sync = mapi_query_auth_types_sync;
 2111 
 2112     store_class = CAMEL_STORE_CLASS (class);
 2113     store_class->can_refresh_folder = mapi_store_can_refresh_folder;
 2114     store_class->get_folder_sync = mapi_store_get_folder_sync;
 2115     store_class->get_folder_info_sync = mapi_store_get_folder_info_sync;
 2116     store_class->get_junk_folder_sync = mapi_store_get_junk_folder_sync;
 2117     store_class->get_trash_folder_sync = mapi_store_get_trash_folder_sync;
 2118     store_class->create_folder_sync = mapi_store_create_folder_sync;
 2119     store_class->delete_folder_sync = mapi_store_delete_folder_sync;
 2120     store_class->rename_folder_sync = mapi_store_rename_folder_sync;
 2121 }
 2122 
 2123 static void
 2124 camel_subscribable_init (CamelSubscribableInterface *iface)
 2125 {
 2126     iface->folder_is_subscribed = mapi_store_folder_is_subscribed;
 2127     iface->subscribe_folder_sync = mapi_store_subscribe_folder_sync;
 2128     iface->unsubscribe_folder_sync = mapi_store_unsubscribe_folder_sync;
 2129 }
 2130 
 2131 /*
 2132 ** store is already initilyse to NULL or 0 value
 2133 ** class already have a parent_class
 2134 ** nothing must be doing here
 2135 */
 2136 static void
 2137 camel_mapi_store_init (CamelMapiStore *mapi_store)
 2138 {
 2139     mapi_store->priv = camel_mapi_store_get_instance_private (mapi_store);
 2140 
 2141     g_rec_mutex_init (&mapi_store->priv->connection_lock);
 2142     g_rec_mutex_init (&mapi_store->priv->updates_lock);
 2143     mapi_store->priv->updates_cancellable = NULL;
 2144     mapi_store->priv->update_folder_names = NULL;
 2145     mapi_store->priv->update_folder_id = 0;
 2146     mapi_store->priv->update_folder_list_id = 0;
 2147 }
 2148 
 2149 /* service methods */
 2150 static void
 2151 mapi_store_constructed (GObject *object)
 2152 {
 2153     CamelMapiStore  *mapi_store = CAMEL_MAPI_STORE (object);
 2154     CamelStore *store = CAMEL_STORE (object);
 2155     CamelMapiStorePrivate *priv = mapi_store->priv;
 2156     CamelService *service;
 2157     const gchar *user_cache_dir;
 2158     gchar *path = NULL;
 2159 
 2160     /* Chain up to parent's constructed() method. */
 2161     G_OBJECT_CLASS (camel_mapi_store_parent_class)->constructed (object);
 2162 
 2163     service = CAMEL_SERVICE (object);
 2164     mapi_migrate_to_user_cache_dir (service);
 2165 
 2166     user_cache_dir = camel_service_get_user_cache_dir (service);
 2167 
 2168     /*store summary*/
 2169     path = g_build_filename (user_cache_dir, ".summary", NULL);
 2170 
 2171     mapi_store->summary = camel_mapi_store_summary_new ();
 2172     camel_store_summary_set_filename (mapi_store->summary, path);
 2173 
 2174     camel_store_summary_load (mapi_store->summary);
 2175 
 2176     /*Hash Table*/
 2177     priv->id_hash = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, g_free); /* folder ID to folder Full name */
 2178     priv->name_hash = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, g_free); /* folder Full name to folder ID */
 2179     /*priv->parent_hash = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, g_free); / * folder ID to its parent folder ID */
 2180     priv->default_folders = g_hash_table_new_full (g_int_hash, g_int_equal, g_free, g_free); /* default folder type to folder ID */
 2181     priv->container_hash = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, g_free);
 2182 
 2183     camel_store_set_flags (store, (camel_store_get_flags (store) & ~(CAMEL_STORE_VJUNK | CAMEL_STORE_VTRASH)) |
 2184         CAMEL_STORE_REAL_JUNK_FOLDER | CAMEL_STORE_USE_CACHE_DIR);
 2185 
 2186     g_free (path);
 2187 }
 2188 
 2189 static char *
 2190 mapi_get_name(CamelService *service, gboolean brief)
 2191 {
 2192     CamelNetworkSettings *network_settings;
 2193     CamelSettings *settings;
 2194     gchar *host;
 2195     gchar *name;
 2196     gchar *user;
 2197 
 2198     settings = camel_service_ref_settings (service);
 2199 
 2200     network_settings = CAMEL_NETWORK_SETTINGS (settings);
 2201     host = camel_network_settings_dup_host (network_settings);
 2202     user = camel_network_settings_dup_user (network_settings);
 2203 
 2204     g_object_unref (settings);
 2205 
 2206     if (brief) {
 2207         /* Translators: The %s is replaced with a server's host name */
 2208         name = g_strdup_printf(_("Exchange MAPI server %s"), host);
 2209     } else {
 2210         /*To translators : Example string : Exchange MAPI service for
 2211           _username_ on _server host name__*/
 2212         name = g_strdup_printf(_("Exchange MAPI service for %s on %s"),
 2213                        user, host);
 2214     }
 2215 
 2216     g_free (host);
 2217     g_free (user);
 2218 
 2219     return name;
 2220 }
 2221 
 2222 static gboolean
 2223 mapi_connect_sync (CamelService *service,
 2224                    GCancellable *cancellable,
 2225                    GError **error)
 2226 {
 2227     CamelMapiStore *store = CAMEL_MAPI_STORE (service);
 2228     EMapiConnection *conn;
 2229     CamelServiceConnectionStatus status;
 2230     CamelSession *session;
 2231     CamelSettings *settings;
 2232     EMapiProfileData empd = { 0 };
 2233     uint64_t current_size = -1, receive_quota = -1, send_quota = -1;
 2234     gchar *name;
 2235 
 2236     /* Chain up to parent's method. */
 2237     if (!CAMEL_SERVICE_CLASS (camel_mapi_store_parent_class)->connect_sync (service, cancellable, error))
 2238         return FALSE;
 2239 
 2240     if (!camel_offline_store_get_online (CAMEL_OFFLINE_STORE (store))) {
 2241         g_set_error_literal (
 2242             error, CAMEL_SERVICE_ERROR, CAMEL_SERVICE_ERROR_UNAVAILABLE,
 2243             _("Cannot connect to MAPI store in offline mode"));
 2244         return FALSE;
 2245     }
 2246 
 2247     session = camel_service_ref_session (service);
 2248 
 2249     status = camel_service_get_connection_status (service);
 2250     if (status == CAMEL_SERVICE_DISCONNECTED) {
 2251         g_object_unref (session);
 2252         return FALSE;
 2253     }
 2254 
 2255     if (check_for_connection (service, NULL)) {
 2256         g_object_unref (session);
 2257         return TRUE;
 2258     }
 2259 
 2260     name = camel_service_get_name (service, TRUE);
 2261     camel_operation_push_message (cancellable, _("Connecting to “%s”"), name);
 2262 
 2263     settings = camel_service_ref_settings (service);
 2264     e_mapi_util_profiledata_from_settings (&empd, CAMEL_MAPI_SETTINGS (settings));
 2265     g_object_unref (settings);
 2266 
 2267     if (!camel_session_authenticate_sync (session, service, empd.krb_sso ? "MAPIKRB" : NULL, cancellable, error)) {
 2268         camel_operation_pop_message (cancellable);
 2269         g_object_unref (session);
 2270         g_free (name);
 2271         return FALSE;
 2272     }
 2273 
 2274     camel_operation_pop_message (cancellable);
 2275 
 2276     camel_offline_store_set_online_sync (
 2277         CAMEL_OFFLINE_STORE (store), TRUE, cancellable, NULL);
 2278 
 2279     camel_store_summary_save (store->summary);
 2280 
 2281     conn = camel_mapi_store_ref_connection (store, cancellable, error);
 2282     if (!conn) {
 2283         g_object_unref (session);
 2284         g_free (name);
 2285 
 2286         return FALSE;
 2287     }
 2288 
 2289     if (e_mapi_connection_get_store_quotas (conn, NULL, &current_size, &receive_quota, &send_quota, cancellable, NULL)) {
 2290         if (current_size != -1) {
 2291             gchar *msg = NULL;
 2292 
 2293             /* warn/alert when the last 1% lefts from the size quota */
 2294             if (send_quota != -1 && current_size * 0.95 >= send_quota) {
 2295                 if (send_quota != -1 && current_size >= send_quota) {
 2296                     msg = g_strdup_printf (_("Mailbox “%s” is full, no new messages will be received or sent."), name);
 2297                 } else {
 2298                     msg = g_strdup_printf (_("Mailbox “%s” is near its size limit, message send will be disabled soon."), name);
 2299                 }
 2300             } else if (receive_quota != -1 && current_size * 0.95 >= receive_quota) {
 2301                 if (current_size >= receive_quota) {
 2302                     msg = g_strdup_printf (_("Mailbox “%s” is full, no new messages will be received."), name);
 2303                 } else {
 2304                     msg = g_strdup_printf (_("Mailbox “%s” is near its size limit."), name);
 2305                 }
 2306             }
 2307 
 2308             if (msg) {
 2309                 camel_session_user_alert (session, service, CAMEL_SESSION_ALERT_WARNING, msg);
 2310                 g_free (msg);
 2311             }
 2312         }
 2313     }
 2314 
 2315     g_object_unref (conn);
 2316     g_free (name);
 2317 
 2318     g_object_unref (session);
 2319 
 2320     return TRUE;
 2321 }
 2322 
 2323 static gboolean
 2324 mapi_disconnect_sync (CamelService *service,
 2325                       gboolean clean,
 2326                       GCancellable *cancellable,
 2327                       GError **error)
 2328 {
 2329     CamelMapiStore *store = CAMEL_MAPI_STORE (service);
 2330 
 2331     stop_pending_updates (store);
 2332 
 2333     g_rec_mutex_lock (&store->priv->connection_lock);
 2334     if (store->priv->connection) {
 2335         g_signal_handlers_disconnect_by_func (store->priv->connection, camel_mapi_store_server_notification_cb, store);
 2336         e_mapi_connection_disable_notifications (store->priv->connection, NULL, cancellable, error);
 2337 
 2338         /* Close the mapi subsystem */
 2339         e_mapi_connection_disconnect (store->priv->connection, clean, clean ? cancellable : NULL, error);
 2340 
 2341         g_object_unref (store->priv->connection);
 2342         store->priv->connection = NULL;
 2343     }
 2344     g_rec_mutex_unlock (&store->priv->connection_lock);
 2345 
 2346     store->priv->folders_synced = FALSE;
 2347 
 2348     /* Chain up to parent's method. */
 2349     return CAMEL_SERVICE_CLASS (camel_mapi_store_parent_class)->disconnect_sync (service, clean, cancellable, error);
 2350 }
 2351 
 2352 struct ScheduleUpdateData
 2353 {
 2354     GCancellable *cancellable;
 2355     CamelMapiStore *mapi_store;
 2356     GSList *foldernames;
 2357     guint expected_id;
 2358 };
 2359 
 2360 static void
 2361 free_schedule_update_data (gpointer ptr)
 2362 {
 2363     struct ScheduleUpdateData *sud = ptr;
 2364 
 2365     if (!sud)
 2366         return;
 2367 
 2368     if (sud->cancellable)
 2369         g_object_unref (sud->cancellable);
 2370     g_slist_free_full (sud->foldernames, g_free);
 2371     g_slice_free (struct ScheduleUpdateData, sud);
 2372 }
 2373 
 2374 static gpointer
 2375 camel_mapi_folder_update_thread (gpointer user_data)
 2376 {
 2377     struct ScheduleUpdateData *sud = user_data;
 2378     CamelMapiStore *mapi_store;
 2379     GSList *fn;
 2380 
 2381     g_return_val_if_fail (sud != NULL, NULL);
 2382 
 2383     mapi_store = g_object_ref (sud->mapi_store);
 2384 
 2385     for (fn = sud->foldernames; fn && !g_cancellable_is_cancelled (sud->cancellable); fn = fn->next) {
 2386         const gchar *foldername = fn->data;
 2387         CamelFolder *folder;
 2388 
 2389         if (!foldername)
 2390             continue;
 2391 
 2392         folder = camel_store_get_folder_sync (CAMEL_STORE (mapi_store), foldername, 0, sud->cancellable, NULL);
 2393         if (folder) {
 2394             camel_folder_refresh_info_sync (folder, sud->cancellable, NULL);
 2395             g_object_unref (folder);
 2396         }
 2397     }
 2398 
 2399     if (!g_cancellable_is_cancelled (sud->cancellable) &&
 2400         !mapi_store->priv->folders_synced)
 2401         mapi_folders_sync (sud->mapi_store, CAMEL_STORE_FOLDER_INFO_RECURSIVE | CAMEL_STORE_FOLDER_INFO_SUBSCRIBED, sud->cancellable, NULL);
 2402 
 2403     g_object_unref (mapi_store);
 2404 
 2405     free_schedule_update_data (sud);
 2406 
 2407     return NULL;
 2408 }
 2409 
 2410 static void
 2411 run_update_thread (CamelMapiStore *mapi_store,
 2412            GCancellable *cancellable,
 2413            GSList *foldernames)
 2414 {
 2415     struct ScheduleUpdateData *sud;
 2416     GThread *thread;
 2417 
 2418     g_return_if_fail (mapi_store != NULL);
 2419     g_return_if_fail (cancellable != NULL);
 2420 
 2421     sud = g_slice_new0 (struct ScheduleUpdateData);
 2422     sud->mapi_store = mapi_store;
 2423     sud->cancellable = g_object_ref (cancellable);
 2424     sud->foldernames = foldernames;
 2425 
 2426     thread = g_thread_new (NULL, camel_mapi_folder_update_thread, sud);
 2427     g_thread_unref (thread);
 2428 }
 2429 
 2430 static gboolean
 2431 folder_update_cb (gpointer user_data)
 2432 {
 2433     struct ScheduleUpdateData *sud = user_data;
 2434     GSList *foldernames;
 2435 
 2436     g_return_val_if_fail (sud != NULL, FALSE);
 2437 
 2438     if (g_cancellable_is_cancelled (sud->cancellable))
 2439         return FALSE;
 2440 
 2441     g_return_val_if_fail (sud->mapi_store != NULL, FALSE);
 2442     g_return_val_if_fail (sud->mapi_store->priv != NULL, FALSE);
 2443 
 2444     g_rec_mutex_lock (&sud->mapi_store->priv->updates_lock);
 2445     if (sud->expected_id != sud->mapi_store->priv->update_folder_id) {
 2446         g_rec_mutex_unlock (&sud->mapi_store->priv->updates_lock);
 2447         return FALSE;
 2448     }
 2449 
 2450     foldernames = sud->mapi_store->priv->update_folder_names;
 2451     sud->mapi_store->priv->update_folder_names = NULL;
 2452     sud->mapi_store->priv->update_folder_id = 0;
 2453 
 2454     if (!g_cancellable_is_cancelled (sud->cancellable))
 2455         run_update_thread (sud->mapi_store, sud->cancellable, foldernames);
 2456     else
 2457         g_slist_free_full (foldernames, g_free);
 2458 
 2459     g_rec_mutex_unlock (&sud->mapi_store->priv->updates_lock);
 2460 
 2461     return FALSE;
 2462 }
 2463 
 2464 static void
 2465 schedule_folder_update (CamelMapiStore *mapi_store, mapi_id_t fid)
 2466 {
 2467     gchar *fidstr;
 2468     const gchar *foldername;
 2469     struct ScheduleUpdateData *sud;
 2470     CamelStoreInfo *si;
 2471     CamelMapiStoreInfo *msi;
 2472 
 2473     g_return_if_fail (mapi_store != NULL);
 2474     g_return_if_fail (mapi_store->priv != NULL);
 2475 
 2476     si = camel_mapi_store_summary_get_folder_id (mapi_store->summary, fid);
 2477     if (!si)
 2478         return;
 2479 
 2480     msi = (CamelMapiStoreInfo *) si;
 2481     if ((msi->mapi_folder_flags & CAMEL_MAPI_STORE_FOLDER_FLAG_MAIL) == 0) {
 2482         camel_store_info_unref (si);
 2483         return;
 2484     }
 2485 
 2486     camel_store_info_unref (si);
 2487 
 2488     fidstr = e_mapi_util_mapi_id_to_string (fid);
 2489     if (!fidstr)
 2490         return;
 2491 
 2492     foldername = camel_mapi_store_folder_lookup (mapi_store, fidstr);
 2493     g_free (fidstr);
 2494 
 2495     if (!foldername)
 2496         return;
 2497 
 2498     g_rec_mutex_lock (&mapi_store->priv->updates_lock);
 2499     if (!mapi_store->priv->updates_cancellable ||
 2500         g_slist_find_custom (mapi_store->priv->update_folder_names, foldername, (GCompareFunc) g_ascii_strcasecmp) != 0) {
 2501         g_rec_mutex_unlock (&mapi_store->priv->updates_lock);
 2502         return;
 2503     }
 2504 
 2505     sud = g_slice_new0 (struct ScheduleUpdateData);
 2506     sud->cancellable = g_object_ref (mapi_store->priv->updates_cancellable);
 2507     sud->mapi_store = mapi_store;
 2508 
 2509     mapi_store->priv->update_folder_names = g_slist_prepend (mapi_store->priv->update_folder_names, g_strdup (foldername));
 2510     if (mapi_store->priv->update_folder_id)
 2511         g_source_remove (mapi_store->priv->update_folder_id);
 2512     mapi_store->priv->update_folder_id = g_timeout_add_seconds_full (G_PRIORITY_LOW, 5, folder_update_cb, sud, free_schedule_update_data);
 2513     sud->expected_id = mapi_store->priv->update_folder_id;
 2514 
 2515     g_rec_mutex_unlock (&mapi_store->priv->updates_lock);
 2516 }
 2517 
 2518 static gboolean
 2519 folder_list_update_cb (gpointer user_data)
 2520 {
 2521     struct ScheduleUpdateData *sud = user_data;
 2522 
 2523     g_return_val_if_fail (sud != NULL, FALSE);
 2524 
 2525     if (g_cancellable_is_cancelled (sud->cancellable))
 2526         return FALSE;
 2527 
 2528     g_return_val_if_fail (sud->mapi_store != NULL, FALSE);
 2529     g_return_val_if_fail (sud->mapi_store->priv != NULL, FALSE);
 2530 
 2531     g_rec_mutex_lock (&sud->mapi_store->priv->updates_lock);
 2532     if (sud->expected_id != sud->mapi_store->priv->update_folder_list_id) {
 2533         g_rec_mutex_unlock (&sud->mapi_store->priv->updates_lock);
 2534         return FALSE;
 2535     }
 2536 
 2537     sud->mapi_store->priv->folders_synced = FALSE;
 2538     sud->mapi_store->priv->update_folder_list_id = 0;
 2539 
 2540     if (!g_cancellable_is_cancelled (sud->cancellable))
 2541         run_update_thread (sud->mapi_store, sud->cancellable, NULL);
 2542 
 2543     g_rec_mutex_unlock (&sud->mapi_store->priv->updates_lock);
 2544 
 2545     return FALSE;
 2546 }
 2547 
 2548 static void
 2549 schedule_folder_list_update (CamelMapiStore *mapi_store)
 2550 {
 2551     struct ScheduleUpdateData *sud;
 2552 
 2553     g_return_if_fail (mapi_store != NULL);
 2554     g_return_if_fail (mapi_store->priv != NULL);
 2555 
 2556     g_rec_mutex_lock (&mapi_store->priv->updates_lock);
 2557     if (!mapi_store->priv->updates_cancellable) {
 2558         g_rec_mutex_unlock (&mapi_store->priv->updates_lock);
 2559         return;
 2560     }
 2561 
 2562     sud = g_slice_new0 (struct ScheduleUpdateData);
 2563     sud->cancellable = g_object_ref (mapi_store->priv->updates_cancellable);
 2564     sud->mapi_store = mapi_store;
 2565 
 2566     if (mapi_store->priv->update_folder_list_id)
 2567         g_source_remove (mapi_store->priv->update_folder_list_id);
 2568     mapi_store->priv->update_folder_list_id = g_timeout_add_seconds_full (G_PRIORITY_LOW, 5, folder_list_update_cb, sud, free_schedule_update_data);
 2569     sud->expected_id = mapi_store->priv->update_folder_list_id;
 2570 
 2571     g_rec_mutex_unlock (&mapi_store->priv->updates_lock);
 2572 }
 2573 
 2574 static void
 2575 camel_mapi_store_server_notification_cb (EMapiConnection *conn,
 2576                      guint event_mask,
 2577                      gpointer event_data,
 2578                      gpointer user_data)
 2579 {
 2580     CamelMapiStore *mapi_store = user_data;
 2581     mapi_id_t update_folder1 = 0, update_folder2 = 0;
 2582     gboolean update_folder_list = FALSE;
 2583 
 2584     g_return_if_fail (mapi_store != NULL);
 2585     g_return_if_fail (mapi_store->priv != NULL);
 2586 
 2587     switch (event_mask) {
 2588     /* -- Folder Events -- */
 2589     case fnevObjectCreated:
 2590         d (printf ("Event : Folder Created\n"));
 2591         d (mapidump_foldercreated (event_data, "\t"));
 2592         update_folder_list = TRUE;
 2593         break;
 2594     case fnevObjectDeleted:
 2595         d (printf ("Event : Folder Deleted\n"));
 2596         d (mapidump_folderdeleted (event_data, "\t"));
 2597         update_folder_list = TRUE;
 2598         break;
 2599     case fnevObjectMoved:
 2600         d (printf ("Event : Folder Moved\n"));
 2601         d (mapidump_foldermoved (event_data, "\t"));
 2602         update_folder_list = TRUE;
 2603         break;
 2604     case fnevObjectCopied:
 2605         d (printf ("Event : Folder Copied\n"));
 2606         d (mapidump_foldercopied (event_data, "\t"));
 2607         update_folder_list = TRUE;
 2608         break;
 2609 
 2610     /* -- Message Events -- */
 2611     case fnevNewMail:
 2612     case fnevNewMail | fnevMbit: {
 2613         struct NewMailNotification *newmail = event_data;
 2614 
 2615         d (printf ("Event : New mail\n"));
 2616         d (mapidump_newmail (event_data, "\t"));
 2617 
 2618         if (newmail)
 2619             update_folder1 = newmail->FID;
 2620         } break;
 2621     case fnevMbit | fnevObjectCreated: {
 2622         struct MessageCreatedNotification *msgcreated = event_data;
 2623 
 2624         d (printf ("Event : Message created\n"));
 2625         d (mapidump_messagecreated (event_data, "\t"));
 2626 
 2627         if (msgcreated)
 2628             update_folder1 = msgcreated->FID;
 2629         } break;
 2630     case fnevMbit | fnevObjectModified: {
 2631         struct MessageModifiedNotification *msgmodified = event_data;
 2632 
 2633         d (printf ("Event : Message modified\n"));
 2634         d (mapidump_messagemodified (event_data, "\t"));
 2635 
 2636         if (msgmodified)
 2637             update_folder1 = msgmodified->FID;
 2638         } break;
 2639     case fnevMbit | fnevObjectDeleted: {
 2640         struct MessageDeletedNotification *msgdeleted = event_data;
 2641 
 2642         d (printf ("Event : Message deleted\n"));
 2643         d (mapidump_messagedeleted (event_data, "\t"));
 2644 
 2645         if (msgdeleted)
 2646             update_folder1 = msgdeleted->FID;
 2647         } break;
 2648     case fnevMbit | fnevObjectMoved: {
 2649         struct MessageMoveCopyNotification *msgmoved = event_data;
 2650 
 2651         d (printf ("Event : Message moved\n"));
 2652         d (mapidump_messagemoved (event_data, "\t"));
 2653 
 2654         if (msgmoved) {
 2655             update_folder1 = msgmoved->OldFID;
 2656             update_folder2 = msgmoved->FID;
 2657         }
 2658         } break;
 2659     case fnevMbit | fnevObjectCopied: {
 2660         struct MessageMoveCopyNotification *msgcopied = event_data;
 2661 
 2662         d (printf ("Event : Message copied\n"));
 2663         d (mapidump_messagecopied (event_data, "\t"));
 2664 
 2665         if (msgcopied) {
 2666             update_folder1 = msgcopied->OldFID;
 2667             update_folder2 = msgcopied->FID;
 2668         }
 2669         } break;
 2670     default:
 2671         /* Unsupported  */
 2672         break;
 2673     }
 2674 
 2675     if (update_folder1 > 0)
 2676         schedule_folder_update (mapi_store, update_folder1);
 2677     if (update_folder2 > 0)
 2678         schedule_folder_update (mapi_store, update_folder2);
 2679     if (update_folder_list)
 2680         schedule_folder_list_update (mapi_store);
 2681 }
 2682 
 2683 static gboolean
 2684 camel_mapi_add_foreign_folder (CamelMapiStore *mapi_store,
 2685                    CamelMapiStoreInfo *owner_msi,
 2686                    EMapiFolder *mapi_folder,
 2687                    CamelFolderInfo *fi,
 2688                    GError **error)
 2689 {
 2690     gboolean success;
 2691 
 2692     g_return_val_if_fail (CAMEL_IS_MAPI_STORE (mapi_store), FALSE);
 2693     g_return_val_if_fail (owner_msi != NULL, FALSE);
 2694     g_return_val_if_fail (mapi_folder != NULL, FALSE);
 2695     g_return_val_if_fail (fi != NULL, FALSE);
 2696 
 2697     success = camel_mapi_store_summary_add_from_full (mapi_store->summary, fi->full_name,
 2698         e_mapi_folder_get_id (mapi_folder), e_mapi_folder_get_parent_id (mapi_folder),
 2699         CAMEL_STORE_INFO_FOLDER_SUBSCRIBED | CAMEL_FOLDER_NOCHILDREN | CAMEL_FOLDER_SUBSCRIBED,
 2700         CAMEL_MAPI_STORE_FOLDER_FLAG_FOREIGN | CAMEL_MAPI_STORE_FOLDER_FLAG_MAIL,
 2701         owner_msi->foreign_username) != NULL;
 2702 
 2703     if (success) {
 2704         CamelStoreInfo *parent_si;
 2705 
 2706         parent_si = camel_mapi_store_summary_get_folder_id (mapi_store->summary, e_mapi_folder_get_parent_id (mapi_folder));
 2707         if (parent_si) {
 2708             CamelMapiStoreInfo *parent_msi = (CamelMapiStoreInfo *) parent_si;
 2709 
 2710             parent_msi->camel_folder_flags = parent_msi->camel_folder_flags & (~CAMEL_FOLDER_NOCHILDREN);
 2711 
 2712             camel_store_info_unref (parent_si);
 2713         }
 2714 
 2715         owner_msi->camel_folder_flags = owner_msi->camel_folder_flags & (~CAMEL_FOLDER_NOCHILDREN);
 2716 
 2717         camel_store_summary_touch (mapi_store->summary);
 2718 
 2719         camel_mapi_store_announce_subscribed_folder (mapi_store, fi->full_name);
 2720     } else {
 2721         g_set_error (error, E_MAPI_ERROR, MAPI_E_INVALID_PARAMETER,
 2722             _("Cannot add folder “%s”, failed to add to store’s summary"), fi->full_name);
 2723     }
 2724 
 2725     return success;
 2726 }
 2727 
 2728 static gboolean
 2729 mapi_store_unsubscribe_with_subfolders (CamelMapiStore *mapi_store,
 2730                     CamelMapiStoreInfo *parent_msi,
 2731                     GPtrArray *array, /* CamelMapiStoreInfo * */
 2732                     GHashTable *processed_fids, /* gchar * ~> NULL */
 2733                     GCancellable *cancellable,
 2734                     GError **error)
 2735 {
 2736     GSList *subfolders, *link;
 2737     gboolean success = TRUE;
 2738 
 2739     g_return_val_if_fail (CAMEL_IS_MAPI_STORE (mapi_store), FALSE);
 2740     g_return_val_if_fail (parent_msi != NULL, FALSE);
 2741 
 2742     if (!array)
 2743         return TRUE;
 2744 
 2745     subfolders = mapi_store_gather_subfolders (array, parent_msi->folder_id);
 2746     subfolders = g_slist_prepend (subfolders, parent_msi);
 2747 
 2748     for (link = subfolders; link && success; link = g_slist_next (link)) {
 2749         CamelMapiStoreInfo *msi = link->data;
 2750 
 2751         if (msi) {
 2752             g_hash_table_insert (processed_fids, e_mapi_util_mapi_id_to_string (msi->folder_id), NULL);
 2753 
 2754             success = mapi_store_unsubscribe_folder_internal_sync (CAMEL_SUBSCRIBABLE (mapi_store),
 2755                 camel_store_info_get_path ((CamelStoreInfo *) msi),
 2756                 FALSE, cancellable, error);
 2757         }
 2758     }
 2759 
 2760     g_slist_free (subfolders);
 2761 
 2762     return success;
 2763 }
 2764 
 2765 static gboolean
 2766 mapi_store_merge_with_subfolders (CamelMapiStore *mapi_store,
 2767                   GSList *mapi_folders, /* EMapiFolder * */
 2768                   CamelMapiStoreInfo *parent_msi,
 2769                   GPtrArray *array, /* CamelMapiStoreInfo * */
 2770                   GHashTable *processed_fids, /* gchar * ~> NULL */
 2771                   GCancellable *cancellable,
 2772                   GError **error)
 2773 {
 2774     GSList *subfolders, *link;
 2775     GHashTable *existing;
 2776     gboolean success = TRUE;
 2777 
 2778     g_return_val_if_fail (CAMEL_IS_MAPI_STORE (mapi_store), FALSE);
 2779     g_return_val_if_fail (parent_msi != NULL, FALSE);
 2780 
 2781     if (!array)
 2782         return TRUE;
 2783 
 2784     existing = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, NULL);
 2785     subfolders = mapi_store_gather_subfolders (array, parent_msi->folder_id);
 2786 
 2787     for (link = subfolders; link; link = g_slist_next (link)) {
 2788         CamelMapiStoreInfo *msi = link->data;
 2789 
 2790         if (msi) {
 2791             g_hash_table_insert (processed_fids, e_mapi_util_mapi_id_to_string (msi->folder_id), NULL);
 2792             g_hash_table_insert (existing, e_mapi_util_mapi_id_to_string (msi->folder_id), msi);
 2793         }
 2794     }
 2795 
 2796     for (link = mapi_folders; link && success; link = g_slist_next (link)) {
 2797         EMapiFolder *mapi_folder = link->data;
 2798         CamelMapiStoreInfo *msi;
 2799         CamelFolderInfo *fi;
 2800         gchar *fid;
 2801 
 2802         if (!mapi_folder)
 2803             continue;
 2804 
 2805         fi = mapi_convert_to_folder_info (mapi_store, mapi_folder, NULL);
 2806         if (!fi)
 2807             continue;
 2808 
 2809         fid = e_mapi_util_mapi_id_to_string (mapi_folder->folder_id);
 2810         if (!fid) {
 2811             camel_folder_info_free (fi);
 2812             continue;
 2813         }
 2814 
 2815         msi = g_hash_table_lookup (existing, fid);
 2816 
 2817         if (msi) {
 2818             const gchar *path;
 2819 
 2820             path = camel_store_info_get_path ((CamelStoreInfo *) msi);
 2821 
 2822             if (g_strcmp0 (fi->full_name, path) != 0) {
 2823                 mapi_rename_folder_infos (mapi_store, path, fi->full_name);
 2824 
 2825                 g_hash_table_remove (mapi_store->priv->name_hash, path);
 2826                 g_hash_table_remove (mapi_store->priv->id_hash, fid);
 2827 
 2828                 mapi_update_folder_hash_tables (mapi_store, fi->full_name, fid, NULL);
 2829 
 2830                 camel_store_info_set_value ((CamelStoreInfo *) msi, CAMEL_STORE_INFO_PATH, fi->full_name);
 2831                 camel_store_summary_touch (mapi_store->summary);
 2832             }
 2833 
 2834             g_hash_table_remove (existing, fid);
 2835         } else {
 2836             if (e_mapi_folder_get_type (mapi_folder) == E_MAPI_FOLDER_TYPE_MAIL) {
 2837                 success = camel_mapi_add_foreign_folder (mapi_store, parent_msi, mapi_folder, fi, error);
 2838             } else {
 2839                 CamelSettings *settings;
 2840                 gchar *profile;
 2841 
 2842                 settings = camel_service_ref_settings (CAMEL_SERVICE (mapi_store));
 2843                 profile = camel_mapi_settings_dup_profile (CAMEL_MAPI_SETTINGS (settings));
 2844 
 2845                 g_object_unref (settings);
 2846 
 2847                 success = e_mapi_folder_add_as_esource (NULL, e_mapi_folder_get_type (mapi_folder),
 2848                     profile,
 2849                     TRUE /* camel_offline_settings_get_stay_synchronized (CAMEL_OFFLINE_SETTINGS (mapi_settings)) */,
 2850                     E_MAPI_FOLDER_CATEGORY_FOREIGN,
 2851                     parent_msi->foreign_username,
 2852                     e_mapi_folder_get_name (mapi_folder),
 2853                     e_mapi_folder_get_id (mapi_folder),
 2854                     0,
 2855                     cancellable,
 2856                     error);
 2857 
 2858                 g_free (profile);
 2859             }
 2860         }
 2861 
 2862         camel_folder_info_free (fi);
 2863         g_free (fid);
 2864     }
 2865 
 2866     if (success && g_hash_table_size (existing)) {
 2867         GHashTableIter iter;
 2868         gpointer value;
 2869 
 2870         g_hash_table_iter_init (&iter, existing);
 2871         while (success && g_hash_table_iter_next (&iter, NULL, &value)) {
 2872             CamelMapiStoreInfo *msi = value;
 2873 
 2874             if (msi) {
 2875                 success = mapi_store_unsubscribe_folder_internal_sync (CAMEL_SUBSCRIBABLE (mapi_store),
 2876                     camel_store_info_get_path ((CamelStoreInfo *) msi),
 2877                     TRUE, cancellable, error);
 2878             }
 2879         }
 2880     }
 2881 
 2882     camel_store_summary_save (mapi_store->summary);
 2883 
 2884     g_hash_table_destroy (existing);
 2885     g_slist_free (subfolders);
 2886 
 2887     return success;
 2888 }
 2889 
 2890 static void
 2891 mapi_store_update_foreign_subfolders_thread (CamelSession *session,
 2892                          GCancellable *cancellable,
 2893                          gpointer user_data,
 2894                          GError **error)
 2895 {
 2896     CamelMapiStore *mapi_store = user_data;
 2897     EMapiConnection *connection;
 2898     GHashTable *processed_fids;
 2899     GPtrArray *array;
 2900     guint ii;
 2901 
 2902     g_return_if_fail (CAMEL_IS_MAPI_STORE (mapi_store));
 2903 
 2904     connection = camel_mapi_store_ref_connection (mapi_store, cancellable, error);
 2905     if (!connection)
 2906         return;
 2907 
 2908     processed_fids = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, NULL);
 2909 
 2910     array = camel_store_summary_array (mapi_store->summary);
 2911     for (ii = 0; array && ii < array->len; ii++) {
 2912         CamelMapiStoreInfo *msi = g_ptr_array_index (array, ii);
 2913 
 2914         if ((msi->mapi_folder_flags & CAMEL_MAPI_STORE_FOLDER_FLAG_FOREIGN) != 0 &&
 2915             (msi->mapi_folder_flags & CAMEL_MAPI_STORE_FOLDER_FLAG_FOREIGN_WITH_SUBFOLDERS) != 0) {
 2916             gchar *fid = e_mapi_util_mapi_id_to_string (msi->folder_id);
 2917             mapi_object_t obj_folder;
 2918             GSList *mapi_folders = NULL;
 2919             gboolean success = TRUE;
 2920             GError *local_error = NULL;
 2921 
 2922             if (!fid || g_hash_table_contains (processed_fids, fid)) {
 2923                 g_free (fid);
 2924                 continue;
 2925             }
 2926 
 2927             g_hash_table_insert (processed_fids, fid, NULL);
 2928 
 2929             if (!e_mapi_connection_open_foreign_folder (connection, msi->foreign_username, msi->folder_id, &obj_folder, cancellable, &local_error)) {
 2930                 if (!g_cancellable_is_cancelled (cancellable) &&
 2931                     camel_offline_store_get_online (CAMEL_OFFLINE_STORE (mapi_store))) {
 2932                     /* Unsubscribe from it only if it could not be found */
 2933                     if (g_error_matches (local_error, E_MAPI_ERROR, MAPI_E_NOT_FOUND) &&
 2934                         !mapi_store_unsubscribe_with_subfolders (mapi_store, msi, array, processed_fids, cancellable, error)) {
 2935                         g_clear_error (&local_error);
 2936                         break;
 2937                     }
 2938 
 2939                     g_clear_error (&local_error);
 2940                     continue;
 2941                 } else {
 2942                     if (local_error)
 2943                         g_propagate_error (error, local_error);
 2944 
 2945                     make_mapi_error (error, "e_mapi_connection_open_foreign_folder", MAPI_E_CALL_FAILED);
 2946                     break;
 2947                 }
 2948             }
 2949 
 2950             if (e_mapi_connection_get_subfolders_list (connection, &obj_folder, E_MAPI_FOLDER_CATEGORY_FOREIGN,
 2951                  &mapi_folders, camel_mapi_update_operation_progress_cb, NULL, cancellable, NULL)) {
 2952                 success = mapi_store_merge_with_subfolders (mapi_store, mapi_folders, msi, array, processed_fids, cancellable, error);
 2953             }
 2954 
 2955             g_slist_free_full (mapi_folders, (GDestroyNotify) e_mapi_folder_free);
 2956 
 2957             if (!e_mapi_connection_close_folder (connection, &obj_folder, cancellable, error) || !success)
 2958                 break;
 2959         }
 2960     }
 2961 
 2962     camel_store_summary_array_free (mapi_store->summary, array);
 2963     g_hash_table_destroy (processed_fids);
 2964     g_object_unref (connection);
 2965 }
 2966 
 2967 static CamelAuthenticationResult
 2968 mapi_authenticate_sync (CamelService *service,
 2969                         const gchar *mechanism,
 2970                         GCancellable *cancellable,
 2971                         GError **error)
 2972 {
 2973     CamelAuthenticationResult result;
 2974     CamelMapiStore *store = CAMEL_MAPI_STORE (service);
 2975     CamelSession *session;
 2976     CamelSettings *settings;
 2977     CamelMapiSettings *mapi_settings;
 2978     CamelNetworkSettings *network_settings;
 2979     ESourceRegistry *registry;
 2980     EMapiProfileData empd = { 0 };
 2981     const gchar *profile;
 2982     const gchar *password;
 2983     GError *mapi_error = NULL, *krb_error = NULL;
 2984     ENamedParameters *credentials;
 2985 
 2986     settings = camel_service_ref_settings (service);
 2987     mapi_settings = CAMEL_MAPI_SETTINGS (settings);
 2988     network_settings = CAMEL_NETWORK_SETTINGS (settings);
 2989 
 2990     empd.server = camel_network_settings_get_host (network_settings);
 2991     empd.username = camel_network_settings_get_user (network_settings);
 2992     e_mapi_util_profiledata_from_settings (&empd, mapi_settings);
 2993 
 2994     profile = camel_mapi_settings_get_profile (mapi_settings);
 2995 
 2996     if (empd.krb_sso) {
 2997         e_mapi_util_trigger_krb_auth (&empd, &krb_error);
 2998         password = NULL;
 2999     } else {
 3000         password = camel_service_get_password (service);
 3001 
 3002         if (password == NULL) {
 3003             g_set_error_literal (
 3004                 error, CAMEL_SERVICE_ERROR,
 3005                 CAMEL_SERVICE_ERROR_CANT_AUTHENTICATE,
 3006                 _("Authentication password not available"));
 3007             g_object_unref (settings);
 3008             return CAMEL_AUTHENTICATION_ERROR;
 3009         }
 3010     }
 3011 
 3012     credentials = e_named_parameters_new ();
 3013     e_named_parameters_set (credentials, E_SOURCE_CREDENTIAL_PASSWORD, password);
 3014     g_rec_mutex_lock (&store->priv->connection_lock);
 3015     session = camel_service_ref_session (service);
 3016     registry = e_source_registry_new_sync (NULL, NULL);
 3017     store->priv->connection = e_mapi_connection_new (registry, profile, credentials, cancellable, &mapi_error);
 3018     e_named_parameters_free (credentials);
 3019     g_clear_object (&registry);
 3020     if (store->priv->connection && e_mapi_connection_connected (store->priv->connection)) {
 3021         GPtrArray *array;
 3022         guint ii;
 3023 
 3024         result = CAMEL_AUTHENTICATION_ACCEPTED;
 3025 
 3026         if (!store->priv->updates_cancellable)
 3027             store->priv->updates_cancellable = g_cancellable_new ();
 3028 
 3029         g_signal_connect (store->priv->connection, "server-notification", G_CALLBACK (camel_mapi_store_server_notification_cb), store);
 3030 
 3031         if (camel_mapi_settings_get_listen_notifications (mapi_settings))
 3032             e_mapi_connection_enable_notifications (store->priv->connection, NULL, 0, NULL, NULL);
 3033 
 3034         /* Also update folder structures of foreign folders,
 3035            those which are subscribed with subfolders */
 3036         array = camel_store_summary_array (store->summary);
 3037         for (ii = 0; array && ii < array->len; ii++) {
 3038             CamelMapiStoreInfo *msi = g_ptr_array_index (array, ii);
 3039 
 3040             if ((msi->mapi_folder_flags & CAMEL_MAPI_STORE_FOLDER_FLAG_FOREIGN) != 0 &&
 3041                 (msi->mapi_folder_flags & CAMEL_MAPI_STORE_FOLDER_FLAG_FOREIGN_WITH_SUBFOLDERS) != 0) {
 3042                 camel_session_submit_job (session, _("Updating foreign folders"),
 3043                     mapi_store_update_foreign_subfolders_thread,
 3044                     g_object_ref (store), g_object_unref);
 3045                 break;
 3046             }
 3047         }
 3048 
 3049         camel_store_summary_array_free (store->summary, array);
 3050     } else if (!krb_error && (
 3051            g_error_matches (mapi_error, E_MAPI_ERROR, MAPI_E_LOGON_FAILED) ||
 3052            g_error_matches (mapi_error, E_MAPI_ERROR, ecRpcFailed))) {
 3053         g_clear_error (&mapi_error);
 3054         result = CAMEL_AUTHENTICATION_REJECTED;
 3055     } else {
 3056         /* mapi_error should be set */
 3057         g_return_val_if_fail (
 3058             mapi_error != NULL,
 3059             CAMEL_AUTHENTICATION_ERROR);
 3060         if (!e_mapi_utils_propagate_cancelled_error (mapi_error, error)) {
 3061             if (krb_error && mapi_error) {
 3062                 GError *new_error = g_error_new (mapi_error->domain, mapi_error->code,
 3063                     /* Translators: the first '%s' is replaced with a generic error message,
 3064                        the second '%s' is replaced with additional error information. */
 3065                     C_("gssapi_error", "%s (%s)"), mapi_error->message, krb_error->message);
 3066                 g_propagate_error (error, new_error);
 3067             } else if (krb_error) {
 3068                 g_propagate_error (error, krb_error);
 3069                 krb_error = NULL;
 3070             } else if (mapi_error) {
 3071                 g_propagate_error (error, mapi_error);
 3072                 mapi_error = NULL;
 3073             }
 3074 
 3075             g_clear_error (&mapi_error);
 3076             g_clear_error (&krb_error);
 3077         } else {
 3078             g_clear_error (&mapi_error);
 3079         }
 3080         result = CAMEL_AUTHENTICATION_ERROR;
 3081     }
 3082 
 3083     g_rec_mutex_unlock (&store->priv->connection_lock);
 3084 
 3085     g_clear_error (&krb_error);
 3086     g_object_unref (settings);
 3087     g_object_unref (session);
 3088 
 3089     return result;
 3090 }
 3091 
 3092 static GList *
 3093 mapi_query_auth_types_sync (CamelService *service,
 3094                             GCancellable *cancellable,
 3095                             GError **error)
 3096 {
 3097     return NULL;
 3098 }
 3099 
 3100 static gboolean
 3101 hash_check_fid_presence (gpointer key, gpointer value, gpointer folder_id)
 3102 {
 3103     return (g_ascii_strcasecmp (value, folder_id) == 0);
 3104 }
 3105 
 3106 static gboolean
 3107 mapi_fid_is_system_folder (CamelMapiStore *mapi_store, const gchar *fid)
 3108 {
 3109     CamelMapiStorePrivate *priv = mapi_store->priv;
 3110 
 3111     if (!(fid && *fid))
 3112         return FALSE;
 3113 
 3114     return (g_hash_table_find (priv->default_folders, hash_check_fid_presence, (gpointer) fid) != NULL);
 3115 }
 3116 
 3117 static const gchar *
 3118 mapi_system_folder_fid (CamelMapiStore *mapi_store, gint folder_type)
 3119 {
 3120     CamelMapiStorePrivate *priv = mapi_store->priv;
 3121 
 3122     return g_hash_table_lookup (priv->default_folders, &folder_type);
 3123 }
 3124 
 3125 static CamelFolderInfo *
 3126 mapi_build_folder_info (CamelMapiStore *mapi_store, const gchar *parent_name, const gchar *folder_name)
 3127 {
 3128     const gchar *name;
 3129     CamelFolderInfo *fi;
 3130 
 3131     fi = camel_folder_info_new ();
 3132 
 3133     fi->unread = -1;
 3134     fi->total = -1;
 3135 
 3136     if (parent_name && *parent_name)
 3137         fi->full_name = g_strconcat (parent_name, "/", folder_name, NULL);
 3138     else
 3139         fi->full_name = g_strdup (folder_name);
 3140 
 3141     name = strrchr(fi->full_name,'/');
 3142     if (name == NULL)
 3143         name = fi->full_name;
 3144     else
 3145         name++;
 3146 
 3147     fi->display_name = g_strdup (name);
 3148 
 3149     return fi;
 3150 }
 3151 
 3152 gboolean
 3153 camel_mapi_store_connected (CamelMapiStore *mapi_store,
 3154                 GCancellable *cancellable,
 3155                 GError **error)
 3156 {
 3157     return camel_offline_store_get_online (CAMEL_OFFLINE_STORE (mapi_store))
 3158         && camel_service_connect_sync (CAMEL_SERVICE (mapi_store), cancellable, error);
 3159 }
 3160 
 3161 void
 3162 camel_mapi_store_maybe_disconnect (CamelMapiStore *mapi_store,
 3163                    const GError *mapi_error)
 3164 {
 3165     g_return_if_fail (CAMEL_IS_MAPI_STORE (mapi_store));
 3166 
 3167     /* no error or already disconnected */
 3168     g_rec_mutex_lock (&mapi_store->priv->connection_lock);
 3169     if (!mapi_error || !mapi_store->priv->connection) {
 3170         g_rec_mutex_unlock (&mapi_store->priv->connection_lock);
 3171         return;
 3172     }
 3173     g_rec_mutex_unlock (&mapi_store->priv->connection_lock);
 3174 
 3175     if (g_error_matches (mapi_error, E_MAPI_ERROR, ecRpcFailed) ||
 3176         g_error_matches (mapi_error, E_MAPI_ERROR, MAPI_E_CALL_FAILED))
 3177         camel_service_disconnect_sync (CAMEL_SERVICE (mapi_store),
 3178             !g_error_matches (mapi_error, E_MAPI_ERROR, ecRpcFailed),
 3179             NULL, NULL);
 3180 }
 3181 
 3182 static void
 3183 mapi_update_hash_table_type (CamelMapiStore *store, const gchar *full_name, guint *folder_type)
 3184 {
 3185     CamelMapiStorePrivate  *priv = store->priv;
 3186     if (full_name && folder_type) {
 3187         if (!g_hash_table_lookup (priv->container_hash, full_name))
 3188             g_hash_table_insert (priv->container_hash, g_strdup (full_name), folder_type);
 3189         else
 3190             g_free (folder_type);
 3191     } else {
 3192         g_free (folder_type);
 3193     }
 3194 }
 3195 
 3196 static void
 3197 mapi_update_folder_hash_tables (CamelMapiStore *store, const gchar *full_name, const gchar *fid, const gchar *parent_id)
 3198 {
 3199     CamelMapiStorePrivate  *priv = store->priv;
 3200 
 3201     if (fid && full_name) {
 3202         /*id_hash returns the name for a given container id*/
 3203         if (!g_hash_table_lookup (priv->id_hash, fid))
 3204             g_hash_table_insert (priv->id_hash, g_strdup (fid), g_strdup (full_name));
 3205 
 3206         /* name_hash : name <-> fid mapping */
 3207         if (!g_hash_table_lookup (priv->name_hash, full_name))
 3208             g_hash_table_insert (priv->name_hash, g_strdup (full_name), g_strdup (fid));
 3209     }
 3210 
 3211     /*parent_hash returns the parent container id, given an id*/
 3212     /*if (fid && parent_id && !g_hash_table_lookup (priv->parent_hash, fid))
 3213         g_hash_table_insert (priv->parent_hash, g_strdup (fid), g_strdup (parent_id));*/
 3214 
 3215 }
 3216 
 3217 static void
 3218 mapi_folders_update_hash_tables_from_cache (CamelMapiStore *store)
 3219 {
 3220     GPtrArray *array;
 3221     guint ii;
 3222 
 3223     array = camel_store_summary_array (store->summary);
 3224 
 3225     for (ii = 0; ii < array->len; ii++) {
 3226         CamelMapiStoreInfo *msi;
 3227         gchar *fid, *pid;
 3228 
 3229         msi = g_ptr_array_index (array, ii);
 3230 
 3231         fid = e_mapi_util_mapi_id_to_string (msi->folder_id);
 3232         pid = e_mapi_util_mapi_id_to_string (msi->parent_id);
 3233 
 3234         mapi_update_folder_hash_tables (store, camel_store_info_get_path ((CamelStoreInfo *) msi), fid, pid);
 3235 
 3236         g_free (fid);
 3237         g_free (pid);
 3238     }
 3239 
 3240     camel_store_summary_array_free (store->summary, array);
 3241 }
 3242 
 3243 /* static const gchar * */
 3244 
 3245 guint
 3246 mapi_folders_hash_table_type_lookup (CamelMapiStore *store, const gchar *name)
 3247 {
 3248     CamelMapiStorePrivate  *priv = store->priv;
 3249     guint *folder_type = g_hash_table_lookup (priv->container_hash, name);
 3250 
 3251     g_return_val_if_fail (folder_type != NULL, 0);
 3252 
 3253     return *folder_type;
 3254 }
 3255 
 3256 const gchar *
 3257 mapi_folders_hash_table_name_lookup (CamelMapiStore *store, const gchar *fid, gboolean use_cache)
 3258 {
 3259     CamelMapiStorePrivate  *priv = store->priv;
 3260     const gchar *name = g_hash_table_lookup (priv->id_hash, fid);
 3261 
 3262     if (!name && use_cache) {
 3263         mapi_folders_update_hash_tables_from_cache (store);
 3264 
 3265         name = g_hash_table_lookup (priv->id_hash, fid);
 3266     }
 3267 
 3268     return name;
 3269 }
 3270 
 3271 #if 0
 3272 static const gchar *
 3273 mapi_folders_hash_table_fid_lookup (CamelMapiStore *store, const gchar *name,
 3274                     gboolean use_cache)
 3275 {
 3276     CamelMapiStorePrivate  *priv = store->priv;
 3277 
 3278     const gchar *fid = g_hash_table_lookup (priv->name_hash, name);
 3279 
 3280     if (!fid && use_cache)
 3281         mapi_folders_update_hash_tables_from_cache (store);
 3282 
 3283     fid = g_hash_table_lookup (priv->name_hash, name);
 3284 
 3285     return fid;
 3286 }
 3287 #endif
 3288 
 3289 const gchar *
 3290 camel_mapi_store_folder_id_lookup (CamelMapiStore *mapi_store, const gchar *folder_name)
 3291 {
 3292     CamelMapiStorePrivate *priv = mapi_store->priv;
 3293 
 3294     return g_hash_table_lookup (priv->name_hash, folder_name);
 3295 }
 3296 
 3297 const gchar *
 3298 camel_mapi_store_system_folder_fid (CamelMapiStore *mapi_store, guint folder_type)
 3299 {
 3300     return mapi_system_folder_fid (mapi_store, folder_type);
 3301 }
 3302 
 3303 const gchar *
 3304 camel_mapi_store_folder_lookup (CamelMapiStore *mapi_store, const gchar *folder_id)
 3305 {
 3306     CamelMapiStorePrivate *priv = mapi_store->priv;
 3307 
 3308     return g_hash_table_lookup (priv->id_hash, folder_id);
 3309 }
 3310 
 3311 EMapiConnection *
 3312 camel_mapi_store_ref_connection (CamelMapiStore *mapi_store,
 3313                  GCancellable *cancellable,
 3314                  GError **error)
 3315 {
 3316     EMapiConnection *conn;
 3317 
 3318     g_return_val_if_fail (mapi_store != NULL, NULL);
 3319     g_return_val_if_fail (CAMEL_IS_MAPI_STORE (mapi_store), NULL);
 3320     g_return_val_if_fail (mapi_store->priv != NULL, NULL);
 3321 
 3322     g_rec_mutex_lock (&mapi_store->priv->connection_lock);
 3323     if (!mapi_store->priv->connection) {
 3324         g_rec_mutex_unlock (&mapi_store->priv->connection_lock);
 3325 
 3326         if (!camel_mapi_store_connected (mapi_store, cancellable, error))
 3327             return NULL;
 3328 
 3329         g_rec_mutex_lock (&mapi_store->priv->connection_lock);
 3330     }
 3331 
 3332     conn = mapi_store->priv->connection;
 3333     if (conn)
 3334         g_object_ref (conn);
 3335     g_rec_mutex_unlock (&mapi_store->priv->connection_lock);
 3336 
 3337     return conn;
 3338 }
 3339 
 3340 /* ppath contains proposed path, this only makes sure that it's a unique path */
 3341 void
 3342 camel_mapi_store_ensure_unique_path (CamelMapiStore *mapi_store,
 3343                      gchar **ppath)
 3344 {
 3345     gboolean done;
 3346     guint counter = 0;
 3347     gchar *base_path = NULL;
 3348 
 3349     g_return_if_fail (mapi_store != NULL);
 3350     g_return_if_fail (mapi_store->summary != NULL);
 3351     g_return_if_fail (ppath != NULL);
 3352     g_return_if_fail (*ppath != NULL);
 3353 
 3354     done = FALSE;
 3355     while (!done) {
 3356         CamelStoreInfo *si;
 3357 
 3358         done = TRUE;
 3359 
 3360         si = camel_store_summary_path (mapi_store->summary, *ppath);
 3361         if (si) {
 3362             camel_store_info_unref (si);
 3363 
 3364             done = FALSE;
 3365             counter++;
 3366             if (!counter) {
 3367                 g_debug ("%s: Counter overflow", G_STRFUNC);
 3368                 break;
 3369             }
 3370 
 3371             if (!base_path)
 3372                 base_path = *ppath;
 3373             else
 3374                 g_free (*ppath);
 3375 
 3376             *ppath = g_strdup_printf ("%s_%u", base_path, counter);
 3377         }
 3378     }
 3379 
 3380     g_free (base_path);
 3381 }
 3382 
 3383 void
 3384 camel_mapi_store_announce_subscribed_folder (CamelMapiStore *mapi_store,
 3385                          const gchar *path)
 3386 {
 3387     CamelStoreInfo *si;
 3388     CamelFolderInfo *fi;
 3389     CamelMapiStoreInfo *msi;
 3390     gchar **parts, *folder_id_str, *parent_id_str;
 3391     GString *partial_path;
 3392     gint ii;
 3393 
 3394     g_return_if_fail (mapi_store != NULL);
 3395     g_return_if_fail (mapi_store->summary != NULL);
 3396     g_return_if_fail (path != NULL);
 3397 
 3398     si = camel_store_summary_path (mapi_store->summary, path);
 3399     g_return_if_fail (si != NULL);
 3400 
 3401     camel_store_info_unref (si);
 3402 
 3403     parts = g_strsplit (path, "/", -1);
 3404     g_return_if_fail (parts != NULL);
 3405 
 3406     partial_path = g_string_new ("");
 3407 
 3408     /* first announce about virtual parents */
 3409     for (ii = 0; parts[ii]; ii++) {
 3410         if (ii > 0)
 3411             g_string_append_c (partial_path, '/');
 3412         g_string_append (partial_path, parts[ii]);
 3413 
 3414         si = camel_store_summary_path (mapi_store->summary, partial_path->str);
 3415         if (si) {
 3416             /* it's a known path, no need to announce it */
 3417             camel_store_info_unref (si);
 3418         } else {
 3419             /* it's an unknown path, not a real path, thus announce it too,
 3420                to ensure the folder path for this new path will exist
 3421             */
 3422             fi = mapi_build_folder_info (mapi_store, NULL, partial_path->str);
 3423             fi->flags |= CAMEL_FOLDER_NOSELECT | CAMEL_FOLDER_SYSTEM;
 3424 
 3425             camel_store_folder_created (CAMEL_STORE (mapi_store), fi);
 3426             camel_subscribable_folder_subscribed (CAMEL_SUBSCRIBABLE (mapi_store), fi);
 3427 
 3428             camel_folder_info_free (fi);
 3429         }
 3430     }
 3431 
 3432     g_string_free (partial_path, TRUE);
 3433     g_strfreev (parts);
 3434 
 3435     /* finally announce about the path itself */
 3436     si = camel_store_summary_path (mapi_store->summary, path);
 3437     g_return_if_fail (si != NULL);
 3438 
 3439     msi = (CamelMapiStoreInfo *) si;
 3440     folder_id_str = e_mapi_util_mapi_id_to_string (msi->folder_id);
 3441     parent_id_str = e_mapi_util_mapi_id_to_string (msi->parent_id);
 3442 
 3443     fi = mapi_build_folder_info (mapi_store, NULL, camel_store_info_get_path (si));
 3444     fi->flags = msi->camel_folder_flags;
 3445 
 3446     mapi_update_folder_hash_tables (mapi_store, fi->full_name, folder_id_str, parent_id_str);
 3447 
 3448     camel_store_folder_created (CAMEL_STORE (mapi_store), fi);
 3449     camel_subscribable_folder_subscribed (CAMEL_SUBSCRIBABLE (mapi_store), fi);
 3450 
 3451     if ((msi->mapi_folder_flags & CAMEL_MAPI_STORE_FOLDER_FLAG_FOREIGN) != 0 &&
 3452         (msi->mapi_folder_flags & CAMEL_MAPI_STORE_FOLDER_FLAG_FOREIGN_WITH_SUBFOLDERS) != 0) {
 3453         CamelSession *session;
 3454 
 3455         session = camel_service_ref_session (CAMEL_SERVICE (mapi_store));
 3456 
 3457         if (session) {
 3458             camel_session_submit_job (session, _("Updating foreign folders"),
 3459                 mapi_store_update_foreign_subfolders_thread,
 3460                 g_object_ref (mapi_store), g_object_unref);
 3461             g_object_unref (session);
 3462         }
 3463     }
 3464 
 3465     camel_folder_info_free (fi);
 3466     camel_store_info_unref (si);
 3467     g_free (folder_id_str);
 3468     g_free (parent_id_str);
 3469 }