"Fossies" - the Fresh Open Source Software Archive

Member "evolution-mapi-3.46.1/src/addressbook/e-book-backend-mapi.c" (2 Dec 2022, 34999 Bytes) of package /linux/misc/evolution-mapi-3.46.1.tar.xz:


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

    1 /* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
    2 /*
    3  * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com)
    4  * Copyright (C) 2017 Red Hat, Inc. (www.redhat.com)
    5  *
    6  * This program is free software; you can redistribute it and/or
    7  * modify it under the terms of the GNU Lesser General Public
    8  * License as published by the Free Software Foundation; either
    9  * version 2 of the License, or (at your option) version 3.
   10  *
   11  * This program is distributed in the hope that it will be useful,
   12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
   13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
   14  * Lesser General Public License for more details.
   15  *
   16  * You should have received a copy of the GNU Lesser General Public
   17  * License along with the program; if not, see <http://www.gnu.org/licenses/>
   18  *
   19  *
   20  * Authors:
   21  *    Srinivasa Ragavan <sragavan@novell.com>
   22  */
   23 
   24 #include "evolution-mapi-config.h"
   25 
   26 #include <stdlib.h>
   27 #include <string.h>
   28 #include <glib.h>
   29 #include <glib/gstdio.h>
   30 #include <glib/gi18n-lib.h>
   31 
   32 #include <libebook/libebook.h>
   33 #include <libedataserver/libedataserver.h>
   34 #include <camel/camel.h>
   35 
   36 #include "e-mapi-utils.h"
   37 #include "e-mapi-defs.h"
   38 #include "e-source-mapi-folder.h"
   39 
   40 #include "e-book-backend-mapi.h"
   41 
   42 /* default value for "partial-count", upper bound of objects to download during partial search */
   43 #define DEFAULT_PARTIAL_COUNT 50
   44 
   45 struct _EBookBackendMAPIPrivate
   46 {
   47     GRecMutex conn_lock;
   48     EMapiConnection *conn;
   49 
   50     gboolean is_gal;
   51 };
   52 
   53 G_DEFINE_TYPE_WITH_PRIVATE (EBookBackendMAPI, e_book_backend_mapi, E_TYPE_BOOK_META_BACKEND)
   54 
   55 static void
   56 ebb_mapi_error_to_client_error (GError **perror,
   57                 const GError *mapi_error,
   58                 EClientError code,
   59                 const gchar *context)
   60 {
   61     gchar *err_msg = NULL;
   62 
   63     if (!perror)
   64         return;
   65 
   66     if (g_error_matches (mapi_error, G_IO_ERROR, G_IO_ERROR_CANCELLED)) {
   67         g_propagate_error (perror, g_error_copy (mapi_error));
   68         return;
   69     }
   70 
   71     if (code == E_CLIENT_ERROR_OTHER_ERROR && mapi_error && mapi_error->domain == E_MAPI_ERROR) {
   72         /* Change error to more accurate only with OTHER_ERROR */
   73         switch (mapi_error->code) {
   74         case MAPI_E_PASSWORD_CHANGE_REQUIRED:
   75         case MAPI_E_PASSWORD_EXPIRED:
   76             code = E_CLIENT_ERROR_AUTHENTICATION_REQUIRED;
   77             break;
   78         case ecRpcFailed:
   79             code = E_CLIENT_ERROR_REPOSITORY_OFFLINE;
   80             break;
   81         default:
   82             break;
   83         }
   84     }
   85 
   86     if (context)
   87         err_msg = g_strconcat (context, mapi_error ? ": " : NULL, mapi_error ? mapi_error->message : NULL, NULL);
   88 
   89     g_propagate_error (perror, e_client_error_create (code, err_msg ? err_msg : mapi_error ? mapi_error->message : _("Unknown error")));
   90 
   91     g_free (err_msg);
   92 }
   93 
   94 static void
   95 ebb_mapi_lock_connection (EBookBackendMAPI *bbmapi)
   96 {
   97     g_return_if_fail (E_IS_BOOK_BACKEND_MAPI (bbmapi));
   98 
   99     g_rec_mutex_lock (&bbmapi->priv->conn_lock);
  100 }
  101 
  102 static void
  103 ebb_mapi_unlock_connection (EBookBackendMAPI *bbmapi)
  104 {
  105     g_return_if_fail (E_IS_BOOK_BACKEND_MAPI (bbmapi));
  106 
  107     g_rec_mutex_unlock (&bbmapi->priv->conn_lock);
  108 }
  109 
  110 static CamelMapiSettings *
  111 ebb_mapi_get_collection_settings (EBookBackendMAPI *ebbm)
  112 {
  113     ESource *source;
  114     ESource *collection;
  115     ESourceCamel *extension;
  116     ESourceRegistry *registry;
  117     CamelSettings *settings;
  118     const gchar *extension_name;
  119 
  120     source = e_backend_get_source (E_BACKEND (ebbm));
  121     registry = e_book_backend_get_registry (E_BOOK_BACKEND (ebbm));
  122 
  123     extension_name = e_source_camel_get_extension_name ("mapi");
  124     e_source_camel_generate_subtype ("mapi", CAMEL_TYPE_MAPI_SETTINGS);
  125 
  126     /* The collection settings live in our parent data source. */
  127     collection = e_source_registry_find_extension (
  128         registry, source, extension_name);
  129     g_return_val_if_fail (collection != NULL, NULL);
  130 
  131     extension = e_source_get_extension (collection, extension_name);
  132     settings = e_source_camel_get_settings (extension);
  133 
  134     g_object_unref (collection);
  135 
  136     return CAMEL_MAPI_SETTINGS (settings);
  137 }
  138 
  139 static gboolean
  140 ebb_mapi_contacts_open_folder (EBookBackendMAPI *bbmapi,
  141                    mapi_object_t *out_obj_folder,
  142                    GCancellable *cancellable,
  143                    GError **error)
  144 {
  145     ESource *source;
  146     ESourceMapiFolder *ext_mapi_folder;
  147     mapi_id_t fid;
  148     gchar *foreign_username;
  149     gboolean success;
  150 
  151     g_return_val_if_fail (E_IS_BOOK_BACKEND_MAPI (bbmapi), FALSE);
  152     g_return_val_if_fail (bbmapi->priv->conn != NULL, FALSE);
  153     g_return_val_if_fail (out_obj_folder != NULL, FALSE);
  154 
  155     source = e_backend_get_source (E_BACKEND (bbmapi));
  156     ext_mapi_folder = e_source_get_extension (source, E_SOURCE_EXTENSION_MAPI_FOLDER);
  157 
  158     fid = e_source_mapi_folder_get_id (ext_mapi_folder);
  159     foreign_username = e_source_mapi_folder_dup_foreign_username (ext_mapi_folder);
  160 
  161     if (foreign_username && *foreign_username)
  162         success = e_mapi_connection_open_foreign_folder (bbmapi->priv->conn, foreign_username, fid, out_obj_folder, cancellable, error);
  163     else if (e_source_mapi_folder_is_public (ext_mapi_folder))
  164         success = e_mapi_connection_open_public_folder (bbmapi->priv->conn, fid, out_obj_folder, cancellable, error);
  165     else
  166         success = e_mapi_connection_open_personal_folder (bbmapi->priv->conn, fid, out_obj_folder, cancellable, error);
  167 
  168     g_free (foreign_username);
  169 
  170     return success;
  171 }
  172 
  173 static void
  174 ebb_mapi_maybe_disconnect (EBookBackendMAPI *bbmapi,
  175                const GError *mapi_error)
  176 {
  177     g_return_if_fail (E_IS_BOOK_BACKEND_MAPI (bbmapi));
  178 
  179     /* no error or already disconnected */
  180     if (!mapi_error || !bbmapi->priv->conn)
  181         return;
  182 
  183     if (g_error_matches (mapi_error, E_MAPI_ERROR, ecRpcFailed) ||
  184         g_error_matches (mapi_error, E_MAPI_ERROR, MAPI_E_CALL_FAILED)) {
  185         e_mapi_connection_disconnect (bbmapi->priv->conn,
  186             !g_error_matches (mapi_error, E_MAPI_ERROR, ecRpcFailed),
  187             NULL, NULL);
  188         g_clear_object (&bbmapi->priv->conn);
  189     }
  190 }
  191 
  192 static gboolean
  193 ebb_mapi_is_marked_for_offline (EBookBackendMAPI *bbmapi)
  194 {
  195     ESource *source;
  196     ESourceOffline *offline_extension;
  197 
  198     g_return_val_if_fail (E_IS_BOOK_BACKEND_MAPI (bbmapi), FALSE);
  199 
  200     source = e_backend_get_source (E_BACKEND (bbmapi));
  201 
  202     offline_extension = e_source_get_extension (source, E_SOURCE_EXTENSION_OFFLINE);
  203 
  204     return e_source_offline_get_stay_synchronized (offline_extension);
  205 }
  206 
  207 static void
  208 ebb_mapi_server_notification_cb (EMapiConnection *conn,
  209                  guint event_mask,
  210                  gpointer event_data,
  211                  gpointer user_data)
  212 {
  213     EBookBackendMAPI *bbmapi = user_data;
  214     mapi_id_t update_folder1 = 0, update_folder2 = 0;
  215 
  216     g_return_if_fail (E_IS_BOOK_BACKEND_MAPI (bbmapi));
  217 
  218     switch (event_mask) {
  219     case fnevNewMail:
  220     case fnevNewMail | fnevMbit: {
  221         struct NewMailNotification *newmail = event_data;
  222 
  223         if (newmail)
  224             update_folder1 = newmail->FID;
  225         } break;
  226     case fnevObjectCreated:
  227     case fnevMbit | fnevObjectCreated: {
  228         struct MessageCreatedNotification *msgcreated = event_data;
  229 
  230         if (msgcreated)
  231             update_folder1 = msgcreated->FID;
  232         } break;
  233     case fnevObjectModified:
  234     case fnevMbit | fnevObjectModified: {
  235         struct MessageModifiedNotification *msgmodified = event_data;
  236 
  237         if (msgmodified)
  238             update_folder1 = msgmodified->FID;
  239         } break;
  240     case fnevObjectDeleted:
  241     case fnevMbit | fnevObjectDeleted: {
  242         struct MessageDeletedNotification *msgdeleted = event_data;
  243 
  244         if (msgdeleted)
  245             update_folder1 = msgdeleted->FID;
  246         } break;
  247     case fnevObjectMoved:
  248     case fnevMbit | fnevObjectMoved: {
  249         struct MessageMoveCopyNotification *msgmoved = event_data;
  250 
  251         if (msgmoved) {
  252             update_folder1 = msgmoved->OldFID;
  253             update_folder2 = msgmoved->FID;
  254         }
  255         } break;
  256     case fnevObjectCopied:
  257     case fnevMbit | fnevObjectCopied: {
  258         struct MessageMoveCopyNotification *msgcopied = event_data;
  259 
  260         if (msgcopied) {
  261             update_folder1 = msgcopied->OldFID;
  262             update_folder2 = msgcopied->FID;
  263         }
  264         } break;
  265     default:
  266         break;
  267     }
  268 
  269     if (update_folder1 || update_folder2) {
  270         ESource *source;
  271         ESourceMapiFolder *ext_mapi_folder;
  272 
  273         source = e_backend_get_source (E_BACKEND (bbmapi));
  274         ext_mapi_folder = e_source_get_extension (source, E_SOURCE_EXTENSION_MAPI_FOLDER);
  275 
  276         if (update_folder1 == e_source_mapi_folder_get_id (ext_mapi_folder) ||
  277             update_folder2 == e_source_mapi_folder_get_id (ext_mapi_folder)) {
  278             e_book_meta_backend_schedule_refresh (E_BOOK_META_BACKEND (bbmapi));
  279         }
  280     }
  281 }
  282 
  283 static gboolean
  284 ebb_mapi_connect_sync (EBookMetaBackend *meta_backend,
  285                const ENamedParameters *credentials,
  286                ESourceAuthenticationResult *out_auth_result,
  287                gchar **out_certificate_pem,
  288                GTlsCertificateFlags *out_certificate_errors,
  289                GCancellable *cancellable,
  290                GError **error)
  291 {
  292     EBookBackendMAPI *bbmapi;
  293     EMapiConnection *old_conn;
  294     CamelMapiSettings *settings;
  295     ESource *source;
  296     ESourceMapiFolder *ext_mapi_folder;
  297     GError *mapi_error = NULL;
  298 
  299     g_return_val_if_fail (E_IS_BOOK_BACKEND_MAPI (meta_backend), FALSE);
  300     g_return_val_if_fail (out_auth_result != NULL, FALSE);
  301 
  302     bbmapi = E_BOOK_BACKEND_MAPI (meta_backend);
  303 
  304     ebb_mapi_lock_connection (bbmapi);
  305 
  306     if (bbmapi->priv->conn &&
  307         e_mapi_connection_connected (bbmapi->priv->conn)) {
  308         ebb_mapi_unlock_connection (bbmapi);
  309         return TRUE;
  310     }
  311 
  312     settings = ebb_mapi_get_collection_settings (bbmapi);
  313     source = e_backend_get_source (E_BACKEND (bbmapi));
  314     ext_mapi_folder = e_source_get_extension (source, E_SOURCE_EXTENSION_MAPI_FOLDER);
  315 
  316     old_conn = bbmapi->priv->conn;
  317 
  318     bbmapi->priv->conn = e_mapi_connection_new (
  319         e_book_backend_get_registry (E_BOOK_BACKEND (bbmapi)),
  320         camel_mapi_settings_get_profile (settings),
  321         credentials, cancellable, &mapi_error);
  322 
  323     if (!bbmapi->priv->conn) {
  324         bbmapi->priv->conn = e_mapi_connection_find (camel_mapi_settings_get_profile (settings));
  325         if (bbmapi->priv->conn && !e_mapi_connection_connected (bbmapi->priv->conn))
  326             e_mapi_connection_reconnect (bbmapi->priv->conn, credentials, cancellable, &mapi_error);
  327     }
  328 
  329     if (old_conn)
  330         g_signal_handlers_disconnect_by_func (old_conn, G_CALLBACK (ebb_mapi_server_notification_cb), bbmapi);
  331 
  332     g_clear_object (&old_conn);
  333 
  334     if (!bbmapi->priv->conn || mapi_error) {
  335         gboolean is_network_error = mapi_error && mapi_error->domain != E_MAPI_ERROR;
  336 
  337         g_clear_object (&bbmapi->priv->conn);
  338         ebb_mapi_unlock_connection (bbmapi);
  339 
  340         if (is_network_error)
  341             ebb_mapi_error_to_client_error (error, mapi_error, E_CLIENT_ERROR_OTHER_ERROR, NULL);
  342 
  343         g_clear_error (&mapi_error);
  344 
  345         if (is_network_error) {
  346             *out_auth_result = E_SOURCE_AUTHENTICATION_ERROR;
  347         } else if ((!credentials || !e_named_parameters_count (credentials)) && !camel_mapi_settings_get_kerberos (settings)) {
  348             *out_auth_result = E_SOURCE_AUTHENTICATION_REQUIRED;
  349         } else {
  350             *out_auth_result = E_SOURCE_AUTHENTICATION_REJECTED;
  351         }
  352 
  353         return FALSE;
  354     }
  355 
  356     if (!e_book_backend_mapi_get_is_gal (bbmapi) &&
  357         e_source_mapi_folder_get_server_notification (ext_mapi_folder)) {
  358         mapi_object_t obj_folder;
  359         GError *mapi_error = NULL;
  360 
  361         g_signal_connect (bbmapi->priv->conn, "server-notification", G_CALLBACK (ebb_mapi_server_notification_cb), bbmapi);
  362 
  363         if (ebb_mapi_contacts_open_folder (bbmapi, &obj_folder, cancellable, &mapi_error)) {
  364             e_mapi_connection_enable_notifications (bbmapi->priv->conn, &obj_folder,
  365                 fnevObjectCreated | fnevObjectModified | fnevObjectDeleted | fnevObjectMoved | fnevObjectCopied,
  366                 cancellable, &mapi_error);
  367 
  368             e_mapi_connection_close_folder (bbmapi->priv->conn, &obj_folder, cancellable, &mapi_error);
  369         }
  370 
  371         if (mapi_error) {
  372             ebb_mapi_maybe_disconnect (bbmapi, mapi_error);
  373             g_clear_error (&mapi_error);
  374         }
  375     }
  376 
  377     ebb_mapi_unlock_connection (bbmapi);
  378 
  379     *out_auth_result = E_SOURCE_AUTHENTICATION_ACCEPTED;
  380 
  381     return TRUE;
  382 }
  383 
  384 static gboolean
  385 ebb_mapi_disconnect_sync (EBookMetaBackend *meta_backend,
  386               GCancellable *cancellable,
  387               GError **error)
  388 {
  389     EBookBackendMAPI *bbmapi;
  390     gboolean success = TRUE;
  391 
  392     g_return_val_if_fail (E_IS_BOOK_BACKEND_MAPI (meta_backend), FALSE);
  393 
  394     bbmapi = E_BOOK_BACKEND_MAPI (meta_backend);
  395 
  396     ebb_mapi_lock_connection (bbmapi);
  397 
  398     if (bbmapi->priv->conn) {
  399         g_signal_handlers_disconnect_by_func (bbmapi->priv->conn, G_CALLBACK (ebb_mapi_server_notification_cb), bbmapi);
  400 
  401         success = e_mapi_connection_disconnect (bbmapi->priv->conn, FALSE, cancellable, error);
  402         g_clear_object (&bbmapi->priv->conn);
  403     }
  404 
  405     ebb_mapi_unlock_connection (bbmapi);
  406 
  407     return success;
  408 }
  409 
  410 typedef struct _LoadMultipleData {
  411     gboolean is_gal;
  412     gchar *book_uid;
  413     GSList **out_contacts; /* EContact * */
  414 } LoadMultipleData;
  415 
  416 static gboolean
  417 transfer_contacts_cb (EMapiConnection *conn,
  418               TALLOC_CTX *mem_ctx,
  419               /* const */ EMapiObject *object,
  420               guint32 obj_index,
  421               guint32 obj_total,
  422               gpointer user_data,
  423               GCancellable *cancellable,
  424               GError **perror)
  425 {
  426     LoadMultipleData *lmd = user_data;
  427     EContact *contact;
  428 
  429     g_return_val_if_fail (conn != NULL, FALSE);
  430     g_return_val_if_fail (object != NULL, FALSE);
  431     g_return_val_if_fail (lmd != NULL, FALSE);
  432 
  433     contact = e_mapi_book_utils_contact_from_object (conn, object, lmd->book_uid);
  434     if (!contact) {
  435         /* being it GAL, just ignore failures */
  436         return lmd->is_gal;
  437     }
  438 
  439     *lmd->out_contacts = g_slist_prepend (*lmd->out_contacts, contact);
  440 
  441     return TRUE;
  442 }
  443 
  444 static gboolean
  445 ebb_mapi_load_multiple_sync (EBookBackendMAPI *bbmapi,
  446                  const GSList *uids, /* gchar * */
  447                  GSList **out_contacts, /* EContact * */
  448                  GCancellable *cancellable,
  449                  GError **error)
  450 {
  451     LoadMultipleData lmd;
  452     const gchar *error_text;
  453     gint partial_count = -1;
  454     GSList *mids = NULL, *link;
  455     ESource *source;
  456     gboolean success;
  457     GError *mapi_error = NULL;
  458 
  459     g_return_val_if_fail (E_IS_BOOK_BACKEND_MAPI (bbmapi), FALSE);
  460     g_return_val_if_fail (uids != NULL, FALSE);
  461     g_return_val_if_fail (out_contacts != NULL, FALSE);
  462 
  463     source = e_backend_get_source (E_BACKEND (bbmapi));
  464 
  465     if (e_book_backend_mapi_get_is_gal (bbmapi) &&
  466         !ebb_mapi_is_marked_for_offline (bbmapi)) {
  467         ESourceMapiFolder *ext_mapi_folder;
  468 
  469         ext_mapi_folder = e_source_get_extension (source, E_SOURCE_EXTENSION_MAPI_FOLDER);
  470         if (e_source_mapi_folder_get_allow_partial (ext_mapi_folder)) {
  471             partial_count = e_source_mapi_folder_get_partial_count (ext_mapi_folder);
  472 
  473             if (partial_count <= 0)
  474                 partial_count = DEFAULT_PARTIAL_COUNT;
  475         }
  476     }
  477 
  478     for (link = (GSList *) uids; link && (partial_count == -1 || partial_count > 0); link = g_slist_next (link)) {
  479         mapi_id_t *pmid, mid;
  480 
  481         if (e_mapi_util_mapi_id_from_string  (link->data, &mid)) {
  482             pmid = g_new0 (mapi_id_t, 1);
  483             *pmid = mid;
  484 
  485             mids = g_slist_prepend (mids, pmid);
  486 
  487             if (partial_count > 0)
  488                 partial_count--;
  489         }
  490     }
  491 
  492     lmd.is_gal = e_book_backend_mapi_get_is_gal (bbmapi);
  493     lmd.book_uid = e_source_dup_uid (source);
  494     lmd.out_contacts = out_contacts;
  495 
  496     ebb_mapi_lock_connection (bbmapi);
  497 
  498     if (e_book_backend_mapi_get_is_gal (bbmapi)) {
  499         error_text = _("Failed to fetch GAL entries");
  500 
  501         success = e_mapi_connection_transfer_gal_objects (bbmapi->priv->conn, mids, NULL, NULL, transfer_contacts_cb, &lmd, cancellable, &mapi_error);
  502     } else {
  503         mapi_object_t obj_folder;
  504 
  505         error_text = _("Failed to transfer contacts from a server");
  506 
  507         success = ebb_mapi_contacts_open_folder (bbmapi, &obj_folder, cancellable, &mapi_error);
  508 
  509         if (success) {
  510             success = e_mapi_connection_transfer_objects (bbmapi->priv->conn, &obj_folder, mids, transfer_contacts_cb, &lmd, cancellable, &mapi_error);
  511 
  512             e_mapi_connection_close_folder (bbmapi->priv->conn, &obj_folder, cancellable, &mapi_error);
  513         }
  514     }
  515 
  516     if (mapi_error) {
  517         ebb_mapi_maybe_disconnect (bbmapi, mapi_error);
  518         ebb_mapi_error_to_client_error (error, mapi_error, E_CLIENT_ERROR_OTHER_ERROR, error_text);
  519         g_error_free (mapi_error);
  520 
  521         success = FALSE;
  522     }
  523 
  524     ebb_mapi_unlock_connection (bbmapi);
  525 
  526     g_slist_free_full (mids, g_free);
  527     g_free (lmd.book_uid);
  528 
  529     return success;
  530 }
  531 
  532 static gboolean
  533 ebb_mapi_preload_infos_sync (EBookBackendMAPI *bbmapi,
  534                  GSList *created_objects,
  535                  GSList *modified_objects,
  536                  GCancellable *cancellable,
  537                  GError **error)
  538 {
  539     GHashTable *infos;
  540     GSList *uids = NULL, *link;
  541     gboolean success = TRUE;
  542 
  543     g_return_val_if_fail (E_IS_BOOK_BACKEND_MAPI (bbmapi), FALSE);
  544 
  545     infos = g_hash_table_new (g_str_hash, g_str_equal);
  546 
  547     for (link = created_objects; link; link = g_slist_next (link)) {
  548         EBookMetaBackendInfo *nfo = link->data;
  549 
  550         if (nfo && nfo->uid) {
  551             uids = g_slist_prepend (uids, nfo->uid);
  552             g_hash_table_insert (infos, nfo->uid, nfo);
  553         }
  554     }
  555 
  556     for (link = modified_objects; link; link = g_slist_next (link)) {
  557         EBookMetaBackendInfo *nfo = link->data;
  558 
  559         if (nfo && nfo->uid) {
  560             uids = g_slist_prepend (uids, nfo->uid);
  561             g_hash_table_insert (infos, nfo->uid, nfo);
  562         }
  563     }
  564 
  565     uids = g_slist_reverse (uids);
  566     if (uids) {
  567         GSList *contacts = NULL;
  568 
  569         success = ebb_mapi_load_multiple_sync (bbmapi, uids, &contacts, cancellable, error);
  570         if (success) {
  571             for (link = contacts; link; link = g_slist_next (link)) {
  572                 EContact *contact = link->data;
  573 
  574                 if (contact) {
  575                     EBookMetaBackendInfo *nfo = g_hash_table_lookup (infos, e_contact_get_const (contact, E_CONTACT_UID));
  576 
  577                     if (nfo && !nfo->object)
  578                         nfo->object = e_vcard_to_string (E_VCARD (contact), EVC_FORMAT_VCARD_30);
  579                 }
  580             }
  581         }
  582 
  583         g_slist_free_full (contacts, g_object_unref);
  584     }
  585 
  586     g_hash_table_destroy (infos);
  587     g_slist_free (uids);
  588 
  589     return success;
  590 }
  591 
  592 static gboolean
  593 ebb_mapi_get_changes_sync (EBookMetaBackend *meta_backend,
  594                const gchar *last_sync_tag,
  595                gboolean is_repeat,
  596                gchar **out_new_sync_tag,
  597                gboolean *out_repeat,
  598                GSList **out_created_objects,
  599                GSList **out_modified_objects,
  600                GSList **out_removed_objects,
  601                GCancellable *cancellable,
  602                GError **error)
  603 {
  604     EBookBackendMAPI *bbmapi;
  605 
  606     g_return_val_if_fail (E_IS_BOOK_BACKEND_MAPI (meta_backend), FALSE);
  607     g_return_val_if_fail (out_created_objects != NULL, FALSE);
  608     g_return_val_if_fail (out_modified_objects != NULL, FALSE);
  609 
  610     /* Chain up to parent's method */
  611     if (!E_BOOK_META_BACKEND_CLASS (e_book_backend_mapi_parent_class)->get_changes_sync (meta_backend,
  612         last_sync_tag, is_repeat, out_new_sync_tag, out_repeat, out_created_objects,
  613         out_modified_objects, out_removed_objects, cancellable, error)) {
  614         return FALSE;
  615     }
  616 
  617     bbmapi = E_BOOK_BACKEND_MAPI (meta_backend);
  618 
  619     /* Preload some of the contacts in chunk, to speed-up things;
  620        ignore errors, to not break whole update process. */
  621     ebb_mapi_preload_infos_sync (bbmapi, *out_created_objects, *out_modified_objects, cancellable, NULL);
  622 
  623     return TRUE;
  624 }
  625 
  626 static gboolean
  627 ebb_mapi_list_existing_uids_cb (EMapiConnection *conn,
  628                 TALLOC_CTX *mem_ctx,
  629                 const ListObjectsData *object_data,
  630                 guint32 obj_index,
  631                 guint32 obj_total,
  632                 gpointer user_data,
  633                 GCancellable *cancellable,
  634                 GError **perror)
  635 {
  636     GSList **out_existing_objects = user_data;
  637     gchar *uid;
  638 
  639     g_return_val_if_fail (conn != NULL, FALSE);
  640     g_return_val_if_fail (object_data != NULL, FALSE);
  641     g_return_val_if_fail (out_existing_objects != NULL, FALSE);
  642 
  643     uid = e_mapi_util_mapi_id_to_string (object_data->mid);
  644     if (uid) {
  645         gchar *rev;
  646 
  647         rev = e_mapi_book_utils_timet_to_string (object_data->last_modified);
  648 
  649         *out_existing_objects = g_slist_prepend (*out_existing_objects,
  650             e_book_meta_backend_info_new (uid, rev, NULL, NULL));
  651 
  652         g_free (uid);
  653         g_free (rev);
  654     }
  655 
  656     return TRUE;
  657 }
  658 
  659 static gboolean
  660 ebb_mapi_list_existing_with_restrictions_sync (EBookMetaBackend *meta_backend,
  661                            BuildRestrictionsCB build_rs_cb,
  662                            gpointer build_rs_cb_data,
  663                            gchar **out_new_sync_tag,
  664                            GSList **out_existing_objects, /* EBookMetaBackendInfo * */
  665                            GCancellable *cancellable,
  666                            GError **error)
  667 {
  668     EBookBackendMAPI *bbmapi;
  669     const gchar *error_text;
  670     gboolean success;
  671     GError *mapi_error = NULL;
  672 
  673     g_return_val_if_fail (E_IS_BOOK_BACKEND_MAPI (meta_backend), FALSE);
  674     g_return_val_if_fail (out_existing_objects, FALSE);
  675 
  676     *out_existing_objects = NULL;
  677 
  678     bbmapi = E_BOOK_BACKEND_MAPI (meta_backend);
  679 
  680     ebb_mapi_lock_connection (bbmapi);
  681 
  682     if (e_book_backend_mapi_get_is_gal (bbmapi)) {
  683         error_text = _("Failed to fetch GAL entries");
  684 
  685         success = e_mapi_connection_list_gal_objects (bbmapi->priv->conn, NULL, NULL,
  686             ebb_mapi_list_existing_uids_cb, out_existing_objects, cancellable, &mapi_error);
  687     } else {
  688         mapi_object_t obj_folder;
  689 
  690         error_text = _("Failed to list items from a server");
  691 
  692         success = ebb_mapi_contacts_open_folder (bbmapi, &obj_folder, cancellable, &mapi_error);
  693         if (success) {
  694             success = e_mapi_connection_list_objects (bbmapi->priv->conn, &obj_folder, NULL, NULL,
  695                 ebb_mapi_list_existing_uids_cb, out_existing_objects, cancellable, &mapi_error);
  696 
  697             e_mapi_connection_close_folder (bbmapi->priv->conn, &obj_folder, cancellable, &mapi_error);
  698         }
  699     }
  700 
  701     if (mapi_error) {
  702         ebb_mapi_maybe_disconnect (bbmapi, mapi_error);
  703         ebb_mapi_error_to_client_error (error, mapi_error, E_CLIENT_ERROR_OTHER_ERROR, error_text);
  704         g_error_free (mapi_error);
  705 
  706         success = FALSE;
  707     }
  708 
  709     ebb_mapi_unlock_connection (bbmapi);
  710 
  711     return success;
  712 }
  713 
  714 
  715 static gboolean
  716 ebb_mapi_list_existing_sync (EBookMetaBackend *meta_backend,
  717                  gchar **out_new_sync_tag,
  718                  GSList **out_existing_objects,
  719                  GCancellable *cancellable,
  720                  GError **error)
  721 {
  722     g_return_val_if_fail (E_IS_BOOK_BACKEND_MAPI (meta_backend), FALSE);
  723 
  724     return ebb_mapi_list_existing_with_restrictions_sync (meta_backend, NULL, NULL,
  725         out_new_sync_tag, out_existing_objects, cancellable, error);
  726 }
  727 
  728 static gboolean
  729 ebb_mapi_load_contact_sync (EBookMetaBackend *meta_backend,
  730                   const gchar *uid,
  731                   const gchar *extra,
  732                   EContact **out_contact,
  733                   gchar **out_extra,
  734                   GCancellable *cancellable,
  735                   GError **error)
  736 {
  737     EBookBackendMAPI *bbmapi;
  738     GSList *uids, *contacts = NULL;
  739     gboolean success;
  740 
  741     g_return_val_if_fail (E_IS_BOOK_BACKEND_MAPI (meta_backend), FALSE);
  742     g_return_val_if_fail (uid != NULL, FALSE);
  743     g_return_val_if_fail (out_contact != NULL, FALSE);
  744 
  745     *out_contact = NULL;
  746 
  747     bbmapi = E_BOOK_BACKEND_MAPI (meta_backend);
  748 
  749     uids = g_slist_prepend (NULL, (gpointer) uid);
  750 
  751     success = ebb_mapi_load_multiple_sync (bbmapi, uids, &contacts, cancellable, error);
  752 
  753     ebb_mapi_unlock_connection (bbmapi);
  754 
  755     if (success && contacts) {
  756         *out_contact = g_object_ref (contacts->data);
  757     }
  758 
  759     g_slist_free_full (contacts, g_object_unref);
  760     g_slist_free (uids);
  761 
  762     return success;
  763 }
  764 
  765 typedef struct _SaveContactData {
  766     EBookBackendMAPI *bbmapi;
  767     EContact *contact;
  768 } SaveContactData;
  769 
  770 static gboolean
  771 ebb_mapi_create_object_cb (EMapiConnection *conn,
  772                TALLOC_CTX *mem_ctx,
  773                EMapiObject **pobject, /* out */
  774                gpointer user_data,
  775                GCancellable *cancellable,
  776                GError **error)
  777 {
  778     SaveContactData *scd = user_data;
  779     const gchar *uid = NULL;
  780     EContact *old_contact = NULL;
  781     gboolean success;
  782 
  783     g_return_val_if_fail (scd != NULL, FALSE);
  784     g_return_val_if_fail (scd->bbmapi != NULL, FALSE);
  785     g_return_val_if_fail (scd->contact != NULL, FALSE);
  786     g_return_val_if_fail (conn != NULL, FALSE);
  787     g_return_val_if_fail (mem_ctx != NULL, FALSE);
  788     g_return_val_if_fail (pobject != NULL, FALSE);
  789 
  790     uid = e_contact_get_const (scd->contact, E_CONTACT_UID);
  791     if (uid) {
  792         EBookCache *book_cache;
  793 
  794         book_cache = e_book_meta_backend_ref_cache (E_BOOK_META_BACKEND (scd->bbmapi));
  795         if (book_cache &&
  796             !e_book_cache_get_contact (book_cache, uid, FALSE, &old_contact, cancellable, NULL)) {
  797             old_contact = NULL;
  798         }
  799 
  800         g_clear_object (&book_cache);
  801     }
  802 
  803     success = e_mapi_book_utils_contact_to_object (scd->contact, old_contact, pobject, mem_ctx, cancellable, error);
  804 
  805     g_clear_object (&old_contact);
  806 
  807     return success;
  808 }
  809 
  810 static gboolean
  811 ebb_mapi_save_contact_sync (EBookMetaBackend *meta_backend,
  812                 gboolean overwrite_existing,
  813                 EConflictResolution conflict_resolution,
  814                 /* const */ EContact *contact,
  815                 const gchar *extra,
  816                 guint32 opflags,
  817                 gchar **out_new_uid,
  818                 gchar **out_new_extra,
  819                 GCancellable *cancellable,
  820                 GError **error)
  821 {
  822     EBookBackendMAPI *bbmapi;
  823     mapi_object_t obj_folder;
  824     mapi_id_t mid = 0;
  825     gboolean success;
  826     GError *mapi_error = NULL;
  827 
  828     g_return_val_if_fail (E_IS_BOOK_BACKEND_MAPI (meta_backend), FALSE);
  829     g_return_val_if_fail (E_IS_CONTACT (contact), FALSE);
  830     g_return_val_if_fail (out_new_uid != NULL, FALSE);
  831 
  832     *out_new_uid = NULL;
  833 
  834     bbmapi = E_BOOK_BACKEND_MAPI (meta_backend);
  835 
  836     if (e_book_backend_mapi_get_is_gal (bbmapi)) {
  837         g_propagate_error (error, e_client_error_create (E_CLIENT_ERROR_PERMISSION_DENIED, NULL));
  838         return FALSE;
  839     }
  840 
  841     ebb_mapi_lock_connection (bbmapi);
  842 
  843     success = ebb_mapi_contacts_open_folder (bbmapi, &obj_folder, cancellable, &mapi_error);
  844     if (success) {
  845         SaveContactData scd;
  846 
  847         scd.bbmapi = bbmapi;
  848         scd.contact = contact;
  849 
  850         if (overwrite_existing) {
  851             success = e_mapi_util_mapi_id_from_string (e_contact_get_const (contact, E_CONTACT_UID), &mid) &&
  852                 e_mapi_connection_modify_object (bbmapi->priv->conn, &obj_folder, mid,
  853                     ebb_mapi_create_object_cb, &scd, cancellable, &mapi_error);
  854 
  855         } else {
  856             success = e_mapi_connection_create_object (bbmapi->priv->conn, &obj_folder, E_MAPI_CREATE_FLAG_NONE,
  857                 ebb_mapi_create_object_cb, &scd, &mid, cancellable, &mapi_error);
  858         }
  859 
  860         e_mapi_connection_close_folder (bbmapi->priv->conn, &obj_folder, cancellable, &mapi_error);
  861     }
  862 
  863     if (mapi_error || !mid) {
  864         ebb_mapi_maybe_disconnect (bbmapi, mapi_error);
  865         ebb_mapi_error_to_client_error (error, mapi_error, E_CLIENT_ERROR_OTHER_ERROR,
  866             overwrite_existing ? _("Failed to modify item on a server") : _("Failed to create item on a server"));
  867         g_clear_error (&mapi_error);
  868 
  869         success = FALSE;
  870     }
  871 
  872     ebb_mapi_unlock_connection (bbmapi);
  873 
  874     if (success)
  875         *out_new_uid = e_mapi_util_mapi_id_to_string (mid);
  876 
  877     return success;
  878 }
  879 
  880 static gboolean
  881 ebb_mapi_remove_contact_sync (EBookMetaBackend *meta_backend,
  882                   EConflictResolution conflict_resolution,
  883                   const gchar *uid,
  884                   const gchar *extra,
  885                   const gchar *object,
  886                   guint32 opflags,
  887                   GCancellable *cancellable,
  888                   GError **error)
  889 {
  890     EBookBackendMAPI *bbmapi;
  891     mapi_id_t mid = 0;
  892     gboolean success = TRUE;
  893     GError *mapi_error = NULL;
  894 
  895     g_return_val_if_fail (E_IS_BOOK_BACKEND_MAPI (meta_backend), FALSE);
  896     g_return_val_if_fail (uid != NULL, FALSE);
  897 
  898     bbmapi = E_BOOK_BACKEND_MAPI (meta_backend);
  899 
  900     if (e_book_backend_mapi_get_is_gal (bbmapi)) {
  901         g_propagate_error (error, e_client_error_create (E_CLIENT_ERROR_PERMISSION_DENIED, NULL));
  902         return FALSE;
  903     }
  904 
  905     if (e_mapi_util_mapi_id_from_string (uid, &mid)) {
  906         mapi_object_t obj_folder;
  907 
  908         ebb_mapi_lock_connection (bbmapi);
  909 
  910         success = ebb_mapi_contacts_open_folder (bbmapi, &obj_folder, cancellable, &mapi_error);
  911         if (success) {
  912             GSList *mids;
  913 
  914             mids = g_slist_prepend (NULL, &mid);
  915 
  916             success = e_mapi_connection_remove_items (bbmapi->priv->conn, &obj_folder, mids, cancellable, &mapi_error);
  917 
  918             e_mapi_connection_close_folder (bbmapi->priv->conn, &obj_folder, cancellable, &mapi_error);
  919 
  920             g_slist_free (mids);
  921         }
  922 
  923         ebb_mapi_unlock_connection (bbmapi);
  924     }
  925 
  926     if (mapi_error || !mid) {
  927         ebb_mapi_maybe_disconnect (bbmapi, mapi_error);
  928         ebb_mapi_error_to_client_error (error, mapi_error, E_CLIENT_ERROR_OTHER_ERROR, _("Failed to remove item from a server"));
  929         g_clear_error (&mapi_error);
  930 
  931         success = FALSE;
  932     }
  933 
  934     return success;
  935 }
  936 
  937 static gboolean
  938 ebb_mapi_update_cache_for_expression (EBookBackendMAPI *bbmapi,
  939                       const gchar *expr,
  940                       GCancellable *cancellable,
  941                       GError **error)
  942 {
  943     EBookMetaBackend *meta_backend;
  944     GSList *found_infos = NULL;
  945     gboolean success = TRUE;
  946 
  947     g_return_val_if_fail (E_IS_BOOK_BACKEND_MAPI (bbmapi), FALSE);
  948 
  949     meta_backend = E_BOOK_META_BACKEND (bbmapi);
  950 
  951     ebb_mapi_lock_connection (bbmapi);
  952 
  953     /* Search only if not searching for everything */
  954     if (expr && *expr && g_ascii_strcasecmp (expr, "(contains \"x-evolution-any-field\" \"\")") != 0) {
  955         success = e_book_meta_backend_ensure_connected_sync (meta_backend, cancellable, error) &&
  956             ebb_mapi_list_existing_with_restrictions_sync (meta_backend,
  957                 e_mapi_book_utils_build_sexp_restriction, (gpointer) expr,
  958                 NULL, &found_infos, cancellable, error);
  959 
  960         if (success) {
  961             GSList *created_objects = NULL, *modified_objects = NULL;
  962 
  963             success = e_book_meta_backend_split_changes_sync (meta_backend, found_infos, &created_objects,
  964                 &modified_objects, NULL, cancellable, error);
  965             if (success)
  966                 success = ebb_mapi_preload_infos_sync (bbmapi, created_objects, modified_objects, cancellable, error);
  967             if (success)
  968                 success = e_book_meta_backend_process_changes_sync (meta_backend, created_objects,
  969                     modified_objects, NULL, cancellable, error);
  970 
  971             g_slist_free_full (created_objects, e_book_meta_backend_info_free);
  972             g_slist_free_full (modified_objects, e_book_meta_backend_info_free);
  973         }
  974 
  975         g_slist_free_full (found_infos, e_book_meta_backend_info_free);
  976     }
  977 
  978     ebb_mapi_unlock_connection (bbmapi);
  979 
  980     return success;
  981 }
  982 
  983 static gboolean
  984 ebb_mapi_search_sync (EBookMetaBackend *meta_backend,
  985               const gchar *expr,
  986               gboolean meta_contact,
  987               GSList **out_contacts,
  988               GCancellable *cancellable,
  989               GError **error)
  990 {
  991     g_return_val_if_fail (E_IS_BOOK_BACKEND_MAPI (meta_backend), FALSE);
  992 
  993     /* Ignore errors, just try its best */
  994     ebb_mapi_update_cache_for_expression (E_BOOK_BACKEND_MAPI (meta_backend), expr, cancellable, NULL);
  995 
  996     /* Chain up to parent's method */
  997     return E_BOOK_META_BACKEND_CLASS (e_book_backend_mapi_parent_class)->search_sync (meta_backend, expr, meta_contact,
  998         out_contacts, cancellable, error);
  999 }
 1000 
 1001 static gboolean
 1002 ebb_mapi_search_uids_sync (EBookMetaBackend *meta_backend,
 1003                const gchar *expr,
 1004                GSList **out_uids,
 1005                GCancellable *cancellable,
 1006                GError **error)
 1007 {
 1008     g_return_val_if_fail (E_IS_BOOK_BACKEND_MAPI (meta_backend), FALSE);
 1009 
 1010     /* Ignore errors, just try its best */
 1011     ebb_mapi_update_cache_for_expression (E_BOOK_BACKEND_MAPI (meta_backend), expr, cancellable, NULL);
 1012 
 1013     /* Chain up to parent's method */
 1014     return E_BOOK_META_BACKEND_CLASS (e_book_backend_mapi_parent_class)->search_uids_sync (meta_backend, expr,
 1015         out_uids, cancellable, error);
 1016 }
 1017 
 1018 static gchar *
 1019 ebb_mapi_get_backend_property (EBookBackend *backend,
 1020                    const gchar *prop_name)
 1021 {
 1022     EBookBackendMAPI *bbmapi;
 1023 
 1024     g_return_val_if_fail (prop_name != NULL, NULL);
 1025 
 1026     bbmapi = E_BOOK_BACKEND_MAPI (backend);
 1027 
 1028     if (g_str_equal (prop_name, CLIENT_BACKEND_PROPERTY_CAPABILITIES)) {
 1029         return g_strjoin (",",
 1030             "net",
 1031             "contact-lists",
 1032             e_book_meta_backend_get_capabilities (E_BOOK_META_BACKEND (backend)),
 1033             ebb_mapi_is_marked_for_offline (bbmapi) ? "do-initial-query" : NULL,
 1034             NULL);
 1035     } else if (g_str_equal (prop_name, E_BOOK_BACKEND_PROPERTY_REQUIRED_FIELDS)) {
 1036         return g_strdup (e_contact_field_name (E_CONTACT_FILE_AS));
 1037     } else if (g_str_equal (prop_name, E_BOOK_BACKEND_PROPERTY_SUPPORTED_FIELDS)) {
 1038         GSList *fields;
 1039         gchar *prop_value;
 1040 
 1041         fields = e_mapi_book_utils_get_supported_contact_fields ();
 1042         prop_value = e_data_book_string_slist_to_comma_string (fields);
 1043         g_slist_free (fields);
 1044 
 1045         return prop_value;
 1046     }
 1047 
 1048     /* Chain up to parent's method */
 1049     return E_BOOK_BACKEND_CLASS (e_book_backend_mapi_parent_class)->impl_get_backend_property (backend, prop_name);
 1050 }
 1051 
 1052 static gboolean
 1053 ebb_mapi_get_destination_address (EBackend *backend,
 1054                   gchar **host,
 1055                   guint16 *port)
 1056 {
 1057     ESourceRegistry *registry;
 1058     ESource *source;
 1059     gboolean result = FALSE;
 1060 
 1061     g_return_val_if_fail (host != NULL, FALSE);
 1062     g_return_val_if_fail (port != NULL, FALSE);
 1063 
 1064     registry = e_book_backend_get_registry (E_BOOK_BACKEND (backend));
 1065     source = e_backend_get_source (backend);
 1066 
 1067     /* Sanity checking */
 1068     if (!registry || !source || !e_source_get_parent (source))
 1069         return FALSE;
 1070 
 1071     source = e_source_registry_ref_source (registry, e_source_get_parent (source));
 1072     if (!source)
 1073         return FALSE;
 1074 
 1075     if (e_source_has_extension (source, E_SOURCE_EXTENSION_AUTHENTICATION)) {
 1076         ESourceAuthentication *auth = e_source_get_extension (source, E_SOURCE_EXTENSION_AUTHENTICATION);
 1077 
 1078         *host = g_strdup (e_source_authentication_get_host (auth));
 1079         *port = e_source_authentication_get_port (auth);
 1080 
 1081         if (!*port)
 1082             *port = 135;
 1083 
 1084         result = *host && **host;
 1085         if (!result) {
 1086             g_free (*host);
 1087             *host = NULL;
 1088         }
 1089     }
 1090 
 1091     g_object_unref (source);
 1092 
 1093     return result;
 1094 }
 1095 
 1096 static void
 1097 ebb_mapi_constructed (GObject *object)
 1098 {
 1099     EBookBackendMAPI *bbmapi = E_BOOK_BACKEND_MAPI (object);
 1100 
 1101     /* Chaing up to parent's method */
 1102     G_OBJECT_CLASS (e_book_backend_mapi_parent_class)->constructed (object);
 1103 
 1104     /* Reset the connectable, it steals data from Authentication extension,
 1105        where is written no address */
 1106     e_backend_set_connectable (E_BACKEND (object), NULL);
 1107 
 1108     e_book_backend_set_writable (E_BOOK_BACKEND (bbmapi), !e_book_backend_mapi_get_is_gal (bbmapi));
 1109 }
 1110 
 1111 static void
 1112 ebb_mapi_dispose (GObject *object)
 1113 {
 1114     EBookBackendMAPI *bbmapi = E_BOOK_BACKEND_MAPI (object);
 1115 
 1116     g_clear_object (&bbmapi->priv->conn);
 1117 
 1118     /* Chain up to parent's method */
 1119     G_OBJECT_CLASS (e_book_backend_mapi_parent_class)->dispose (object);
 1120 }
 1121 
 1122 static void
 1123 ebb_mapi_finalize (GObject *object)
 1124 {
 1125     EBookBackendMAPI *bbmapi = E_BOOK_BACKEND_MAPI (object);
 1126 
 1127     g_rec_mutex_clear (&bbmapi->priv->conn_lock);
 1128 
 1129     /* Chain up to parent's method */
 1130     G_OBJECT_CLASS (e_book_backend_mapi_parent_class)->finalize (object);
 1131 }
 1132 
 1133 static void
 1134 e_book_backend_mapi_class_init (EBookBackendMAPIClass *klass)
 1135 {
 1136     GObjectClass *object_class;
 1137     EBackendClass *backend_class;
 1138     EBookBackendClass *book_backend_class;
 1139     EBookMetaBackendClass *meta_backend_class;
 1140 
 1141     meta_backend_class = E_BOOK_META_BACKEND_CLASS (klass);
 1142     meta_backend_class->backend_module_directory = BACKENDDIR;
 1143     meta_backend_class->backend_module_filename = "libebookbackendmapi.so";
 1144     meta_backend_class->connect_sync = ebb_mapi_connect_sync;
 1145     meta_backend_class->disconnect_sync = ebb_mapi_disconnect_sync;
 1146     meta_backend_class->get_changes_sync = ebb_mapi_get_changes_sync;
 1147     meta_backend_class->list_existing_sync = ebb_mapi_list_existing_sync;
 1148     meta_backend_class->load_contact_sync = ebb_mapi_load_contact_sync;
 1149     meta_backend_class->save_contact_sync = ebb_mapi_save_contact_sync;
 1150     meta_backend_class->remove_contact_sync = ebb_mapi_remove_contact_sync;
 1151     meta_backend_class->search_sync = ebb_mapi_search_sync;
 1152     meta_backend_class->search_uids_sync = ebb_mapi_search_uids_sync;
 1153 
 1154     book_backend_class = E_BOOK_BACKEND_CLASS (klass);
 1155     book_backend_class->impl_get_backend_property = ebb_mapi_get_backend_property;
 1156 
 1157     backend_class = E_BACKEND_CLASS (klass);
 1158     backend_class->get_destination_address = ebb_mapi_get_destination_address;
 1159 
 1160     object_class = G_OBJECT_CLASS (klass);
 1161     object_class->constructed = ebb_mapi_constructed;
 1162     object_class->dispose = ebb_mapi_dispose;
 1163     object_class->finalize = ebb_mapi_finalize;
 1164 }
 1165 
 1166 static void
 1167 e_book_backend_mapi_init (EBookBackendMAPI *bbmapi)
 1168 {
 1169     bbmapi->priv = e_book_backend_mapi_get_instance_private (bbmapi);
 1170 
 1171     g_rec_mutex_init (&bbmapi->priv->conn_lock);
 1172 }
 1173 
 1174 void
 1175 e_book_backend_mapi_set_is_gal (EBookBackendMAPI *bbmapi,
 1176                 gboolean is_gal)
 1177 {
 1178     g_return_if_fail (E_IS_BOOK_BACKEND_MAPI (bbmapi));
 1179 
 1180     bbmapi->priv->is_gal = is_gal;
 1181 }
 1182 
 1183 gboolean
 1184 e_book_backend_mapi_get_is_gal (EBookBackendMAPI *bbmapi)
 1185 {
 1186     g_return_val_if_fail (E_IS_BOOK_BACKEND_MAPI (bbmapi), FALSE);
 1187 
 1188     return bbmapi->priv->is_gal;
 1189 }