[evolution-mapi] Merge common parts of EBookBackend-s and make it more asynchronous
- From: Milan Crha <mcrha src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [evolution-mapi] Merge common parts of EBookBackend-s and make it more asynchronous
- Date: Wed, 21 Jul 2010 14:06:23 +0000 (UTC)
commit 25f4ad0c57f451a0655e0399ea71ce3ecffb642b
Author: Milan Crha <mcrha redhat com>
Date: Wed Jul 21 16:01:34 2010 +0200
Merge common parts of EBookBackend-s and make it more asynchronous
Make sure to delete
$PREFIX/lib/evolution-data-server-1.2/extensions/libebookbackendmapigal.*
as this one was removed, merged to libebookbackendmapi.*, so if not removed
then e-addressbook-factory claims about two factories trying to register
with the same name.
src/addressbook/Makefile.am | 24 +-
src/addressbook/e-book-backend-mapi-contacts.c | 1202 +++++++++
src/addressbook/e-book-backend-mapi-contacts.h | 56 +
src/addressbook/e-book-backend-mapi-factory.c | 27 +-
src/addressbook/e-book-backend-mapi-gal-factory.c | 51 -
src/addressbook/e-book-backend-mapi-gal.c | 906 +------
src/addressbook/e-book-backend-mapi-gal.h | 32 +-
src/addressbook/e-book-backend-mapi-utils.c | 465 ----
src/addressbook/e-book-backend-mapi-utils.h | 47 -
src/addressbook/e-book-backend-mapi.c | 2998 +++++++++++----------
src/addressbook/e-book-backend-mapi.h | 99 +-
src/libexchangemapi/exchange-mapi-connection.c | 6 +-
src/libexchangemapi/exchange-mapi-connection.h | 2 +-
13 files changed, 3001 insertions(+), 2914 deletions(-)
---
diff --git a/src/addressbook/Makefile.am b/src/addressbook/Makefile.am
index ec55a5f..6a715f7 100644
--- a/src/addressbook/Makefile.am
+++ b/src/addressbook/Makefile.am
@@ -7,22 +7,16 @@ AM_CPPFLAGS = \
$(LIBEDATABOOK_CFLAGS) \
$(LIBMAPI_CFLAGS)
-extension_LTLIBRARIES = libebookbackendmapi.la \
- libebookbackendmapigal.la
+extension_LTLIBRARIES = libebookbackendmapi.la
libebookbackendmapi_la_SOURCES = \
e-book-backend-mapi.c \
e-book-backend-mapi.h \
- e-book-backend-mapi-utils.c \
- e-book-backend-mapi-utils.h \
- e-book-backend-mapi-factory.c
-
-libebookbackendmapigal_la_SOURCES = \
+ e-book-backend-mapi-contacts.c \
+ e-book-backend-mapi-contacts.h \
e-book-backend-mapi-gal.c \
e-book-backend-mapi-gal.h \
- e-book-backend-mapi-utils.c \
- e-book-backend-mapi-utils.h \
- e-book-backend-mapi-gal-factory.c
+ e-book-backend-mapi-factory.c
libebookbackendmapi_la_LIBADD = \
$(top_builddir)/src/libexchangemapi/libexchangemapi-1.0.la \
@@ -31,17 +25,7 @@ libebookbackendmapi_la_LIBADD = \
$(LIBEDATABOOK_LIBS) \
$(LIBMAPI_LIBS)
-libebookbackendmapigal_la_LIBADD = \
- $(top_builddir)/src/libexchangemapi/libexchangemapi-1.0.la \
- $(LIBEBACKEND_LIBS) \
- $(LIBEBOOK_LIBS) \
- $(LIBEDATABOOK_LIBS) \
- $(LIBMAPI_LIBS)
-
libebookbackendmapi_la_LDFLAGS = \
-module -avoid-version $(NO_UNDEFINED)
-libebookbackendmapigal_la_LDFLAGS = \
- -module -avoid-version $(NO_UNDEFINED)
-
-include $(top_srcdir)/git.mk
diff --git a/src/addressbook/e-book-backend-mapi-contacts.c b/src/addressbook/e-book-backend-mapi-contacts.c
new file mode 100644
index 0000000..71a45eb
--- /dev/null
+++ b/src/addressbook/e-book-backend-mapi-contacts.c
@@ -0,0 +1,1202 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
+/*
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) version 3.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with the program; if not, see <http://www.gnu.org/licenses/>
+ *
+ *
+ * Authors:
+ * Srinivasa Ragavan <sragavan novell com>
+ *
+ * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com)
+ *
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <stdlib.h>
+#include <fcntl.h>
+#include <string.h>
+#include <glib.h>
+#include <glib/gstdio.h>
+#include <glib/gi18n-lib.h>
+
+#include <sys/time.h>
+/*
+** #include <glib/gi18n-lib.h>
+*/
+
+#include <libedataserver/e-sexp.h>
+#include "libedataserver/e-flag.h"
+#include <libebook/e-contact.h>
+#include <camel/camel.h>
+
+#include <libedata-book/e-book-backend-sexp.h>
+#include <libedata-book/e-data-book.h>
+#include <libedata-book/e-data-book-view.h>
+#include <libedata-book/e-book-backend-cache.h>
+#include <libedata-book/e-book-backend-summary.h>
+
+#include "e-book-backend-mapi-contacts.h"
+
+G_DEFINE_TYPE (EBookBackendMAPIContacts, e_book_backend_mapi_contacts, E_TYPE_BOOK_BACKEND_MAPI)
+
+struct _EBookBackendMAPIContactsPrivate
+{
+ mapi_id_t fid;
+ gboolean is_public_folder;
+};
+
+static gboolean
+build_restriction_emails_contains (struct mapi_SRestriction *res, const gchar *query)
+{
+ gchar *email=NULL, *tmp, *tmp1;
+
+ /* This currently supports "email foo bar soo" */
+ tmp = strdup (query);
+
+ tmp = strstr (tmp, "email");
+ if (tmp ) {
+ tmp = strchr (tmp, '\"');
+ if (tmp && ++tmp) {
+ tmp = strchr (tmp, '\"');
+ if (tmp && ++tmp) {
+ tmp1 = tmp;
+ tmp1 = strchr (tmp1, '\"');
+ if (tmp1) {
+ *tmp1 = 0;
+ email = tmp;
+ }
+ }
+ }
+ }
+
+ if (email==NULL || !strchr (email, '@'))
+ return FALSE;
+
+ res->rt = RES_PROPERTY;
+ res->res.resProperty.relop = RES_PROPERTY;
+ res->res.resProperty.ulPropTag = PROP_TAG(PT_UNICODE, 0x801f); /* EMAIL */
+ res->res.resProperty.lpProp.ulPropTag = PROP_TAG(PT_UNICODE, 0x801f); /* EMAIL*/
+ res->res.resProperty.lpProp.value.lpszA = email;
+
+ return TRUE;
+}
+
+#if 0
+static gboolean
+build_multiple_restriction_emails_contains (ExchangeMapiConnection *conn, mapi_id_t fid, struct mapi_SRestriction *res,
+ struct mapi_SRestriction_or *or_res,
+ const gchar *query, gchar **to_free)
+{
+ gchar *email=NULL, *tmp, *tmp1;
+ //Number of restriction to apply
+ guint res_count = 6;
+
+ g_return_val_if_fail (to_free != NULL, FALSE);
+
+ /* This currently supports "email foo bar soo" */
+ *to_free = strdup (query);
+
+ tmp = strstr (*to_free, "email");
+ if (tmp ) {
+ tmp = strchr (tmp, '\"');
+ if (tmp && ++tmp) {
+ tmp = strchr (tmp, '\"');
+ if (tmp && ++tmp) {
+ tmp1 = tmp;
+ tmp1 = strchr (tmp1, '\"');
+ if (tmp1) {
+ *tmp1 = 0;
+ email = tmp;
+ }
+ }
+ }
+ }
+
+ if (email==NULL || !strchr (email, '@')) {
+ g_free (*to_free);
+ *to_free = NULL;
+
+ return FALSE;
+ }
+
+ or_res[0].rt = RES_CONTENT;
+ or_res[0].res.resContent.fuzzy = FL_FULLSTRING | FL_IGNORECASE;
+ or_res[0].res.resContent.ulPropTag = PR_EMS_AB_MANAGER_T_UNICODE;
+ or_res[0].res.resContent.lpProp.value.lpszA = email;
+
+ or_res[1].rt = RES_CONTENT;
+ or_res[1].res.resContent.fuzzy = FL_FULLSTRING | FL_IGNORECASE;
+ or_res[1].res.resContent.ulPropTag = PR_DISPLAY_NAME_UNICODE;
+ or_res[1].res.resContent.lpProp.value.lpszA = email;
+
+ or_res[2].rt = RES_CONTENT;
+ or_res[2].res.resContent.fuzzy = FL_FULLSTRING | FL_IGNORECASE;
+ or_res[2].res.resContent.ulPropTag = PR_GIVEN_NAME_UNICODE;
+ or_res[2].res.resContent.lpProp.value.lpszA = email;
+
+ or_res[3].rt = RES_CONTENT;
+ or_res[3].res.resContent.fuzzy = FL_FULLSTRING | FL_IGNORECASE;
+ or_res[3].res.resContent.ulPropTag = exchange_mapi_connection_resolve_named_prop (conn, fid, PidLidEmail1OriginalDisplayName, NULL);
+ or_res[3].res.resContent.lpProp.value.lpszA = email;
+
+ or_res[4].rt = RES_CONTENT;
+ or_res[4].res.resContent.fuzzy = FL_FULLSTRING | FL_IGNORECASE;
+ or_res[4].res.resContent.ulPropTag = exchange_mapi_connection_resolve_named_prop (conn, fid, PidLidEmail2OriginalDisplayName, NULL);
+ or_res[4].res.resContent.lpProp.value.lpszA = email;
+
+ or_res[5].rt = RES_CONTENT;
+ or_res[5].res.resContent.fuzzy = FL_FULLSTRING | FL_IGNORECASE;
+ or_res[5].res.resContent.ulPropTag = exchange_mapi_connection_resolve_named_prop (conn, fid, PidLidEmail3OriginalDisplayName, NULL);
+ or_res[5].res.resContent.lpProp.value.lpszA = email;
+
+ res = g_new0 (struct mapi_SRestriction, 1);
+
+ res->rt = RES_OR;
+ res->res.resOr.cRes = res_count;
+ res->res.resOr.res = or_res;
+
+ return TRUE;
+}
+#endif
+
+static uint32_t
+string_to_bin (TALLOC_CTX *mem_ctx, const gchar *str, uint8_t **lpb)
+{
+ uint32_t len, i;
+
+ g_return_val_if_fail (str != NULL, 0);
+ g_return_val_if_fail (lpb != NULL, 0);
+
+ len = strlen (str);
+ g_return_val_if_fail ((len & 1) == 0, 0);
+
+ len = len / 2;
+ *lpb = talloc_zero_array (mem_ctx, uint8_t, len);
+
+ i = 0;
+ while (*str && i < len) {
+ gchar c1 = str[0], c2 = str[1];
+ str += 2;
+
+ g_return_val_if_fail ((c1 >= '0' && c1 <= '9') || (c1 >= 'a' && c1 <= 'f') || (c1 >= 'A' && c1 <= 'F'), 0);
+ g_return_val_if_fail ((c2 >= '0' && c2 <= '9') || (c2 >= 'a' && c2 <= 'f') || (c2 >= 'A' && c2 <= 'F'), 0);
+
+ #define deHex(x) (((x) >= '0' && (x) <= '9') ? ((x) - '0') : (((x) >= 'a' && (x) <= 'f') ? (x) - 'a' + 10 : (x) - 'A' + 10))
+ (*lpb)[i] = (deHex (c1) << 4) | (deHex (c2));
+ #undef deHex
+ i++;
+ }
+
+ return len;
+}
+
+static gint
+cmp_member_id (gconstpointer a, gconstpointer b, gpointer ht)
+{
+ gchar *va, *vb;
+ gint res;
+
+ if (!a)
+ return b ? -1 : 0;
+ if (!b)
+ return 1;
+
+ va = e_vcard_attribute_get_value ((EVCardAttribute *) a);
+ vb = e_vcard_attribute_get_value ((EVCardAttribute *) b);
+
+ res = GPOINTER_TO_INT (g_hash_table_lookup (ht, va)) - GPOINTER_TO_INT (g_hash_table_lookup (ht, vb));
+
+ g_free (va);
+ g_free (vb);
+
+ return res;
+}
+
+typedef struct {
+ EContact *contact;
+ EBookBackendCache *cache;
+} MapiCreateitemData;
+
+static gboolean
+mapi_book_write_props (ExchangeMapiConnection *conn, mapi_id_t fid, TALLOC_CTX *mem_ctx, struct SPropValue **values, uint32_t *n_values, gpointer data)
+{
+ /* Do not make this array static, below function modifies it.
+ The array is used to just ensure named ids are known later. */
+ ResolveNamedIDsData nids[] = {
+ { PidLidDistributionListName, 0 },
+ { PidLidDistributionListOneOffMembers, 0 },
+ { PidLidDistributionListMembers, 0 },
+ { PidLidDistributionListChecksum, 0 },
+ { PidLidFileUnder, 0 },
+ { PidLidFileUnderId, 0 },
+ { PidLidEmail1OriginalDisplayName, 0 },
+ { PidLidEmail1EmailAddress, 0 },
+ { PidLidEmail2EmailAddress, 0 },
+ { PidLidEmail3EmailAddress, 0 },
+ { PidLidHtml, 0 },
+ { PidLidInstantMessagingAddress, 0 },
+ { PidLidHomeAddress, 0 },
+ { PidLidWorkAddress, 0 },
+ { PidLidEmail2OriginalDisplayName, 0 },
+ { PidLidEmail3OriginalDisplayName, 0 }
+ };
+
+ MapiCreateitemData *mcd = data;
+
+ #define set_str_value(hex, val) G_STMT_START { \
+ if (!exchange_mapi_utils_add_spropvalue (mem_ctx, values, n_values, hex, val ? val : "")) \
+ return FALSE; \
+ } G_STMT_END
+
+ #define set_str_named_value(named_id, val) G_STMT_START { \
+ if (!exchange_mapi_utils_add_spropvalue_named_id (conn, fid, mem_ctx, values, n_values, named_id, val ? val : "")) \
+ return FALSE; \
+ } G_STMT_END
+
+ #define set_str_con_value(hex, field_id) G_STMT_START { \
+ if (e_contact_get (mcd->contact, field_id)) { \
+ set_str_value (hex, e_contact_get (mcd->contact, field_id)); \
+ } } G_STMT_END
+
+ #define set_str_named_con_value(named_id, field_id) G_STMT_START { \
+ if (e_contact_get (mcd->contact, field_id)) { \
+ set_str_named_value (named_id, e_contact_get (mcd->contact, field_id)); \
+ } } G_STMT_END
+
+ g_return_val_if_fail (mcd != NULL, FALSE);
+ g_return_val_if_fail (mcd->contact != NULL, FALSE);
+ g_return_val_if_fail (conn != NULL, FALSE);
+ g_return_val_if_fail (mem_ctx != NULL, FALSE);
+ g_return_val_if_fail (values != NULL, FALSE);
+ g_return_val_if_fail (n_values != NULL, FALSE);
+
+ if (!exchange_mapi_connection_resolve_named_props (conn, fid, nids, G_N_ELEMENTS (nids), NULL))
+ return FALSE;
+
+ if (GPOINTER_TO_INT (e_contact_get (mcd->contact, E_CONTACT_IS_LIST))) {
+ EContact *old_contact;
+ GList *local, *l;
+ struct BinaryArray_r *members, *oneoff_members;
+ uint32_t list_size = 0, u32, crc32 = 0;
+ GHashTable *member_values = NULL, *member_ids = NULL;
+
+ old_contact = e_contact_get_const (mcd->contact, E_CONTACT_UID) ? e_book_backend_cache_get_contact (mcd->cache, e_contact_get_const (mcd->contact, E_CONTACT_UID)) : NULL;
+ if (old_contact) {
+ member_values = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, g_free);
+ member_ids = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, NULL);
+
+ local = e_contact_get_attributes (old_contact, E_CONTACT_EMAIL);
+ for (l = local; l; l = l->next) {
+ EVCardAttribute *attr = l->data;
+ GList *param;
+
+ if (!attr)
+ continue;
+
+ param = e_vcard_attribute_get_param (attr, EMA_X_MEMBERVALUE);
+ if (param && param->data && !param->next) {
+ g_hash_table_insert (member_values, e_vcard_attribute_get_value (attr), g_strdup (param->data));
+ }
+
+ param = e_vcard_attribute_get_param (attr, EMA_X_MEMBERID);
+ if (param && param->data && !param->next) {
+ g_hash_table_insert (member_ids, e_vcard_attribute_get_value (attr), GINT_TO_POINTER (atoi (param->data)));
+ }
+ }
+
+ g_object_unref (old_contact);
+ g_list_foreach (local, (GFunc)e_vcard_attribute_free, NULL);
+ g_list_free (local);
+ }
+
+ set_str_value (PR_MESSAGE_CLASS, IPM_DISTLIST);
+ u32 = 0xFFFFFFFF;
+ if (!exchange_mapi_utils_add_spropvalue_named_id (conn, fid, mem_ctx, values, n_values, PidLidFileUnderId, &u32))
+ return FALSE;
+ set_str_named_con_value (PidLidFileUnder, E_CONTACT_FILE_AS);
+ set_str_named_con_value (PidLidDistributionListName, E_CONTACT_FILE_AS);
+ set_str_con_value (PR_DISPLAY_NAME_UNICODE, E_CONTACT_FILE_AS);
+ set_str_con_value (PR_NORMALIZED_SUBJECT_UNICODE, E_CONTACT_FILE_AS);
+
+
+ local = e_contact_get_attributes (mcd->contact, E_CONTACT_EMAIL);
+ if (member_ids)
+ local = g_list_sort_with_data (local, cmp_member_id, member_ids);
+
+ members = talloc_zero (mem_ctx, struct BinaryArray_r);
+ members->cValues = 0;
+ members->lpbin = talloc_zero_array (mem_ctx, struct Binary_r, g_list_length (local));
+
+ oneoff_members = talloc_zero (mem_ctx, struct BinaryArray_r);
+ oneoff_members->cValues = 0;
+ oneoff_members->lpbin = talloc_zero_array (mem_ctx, struct Binary_r, g_list_length (local));
+
+ for (l = local; l; l = l->next) {
+ EVCardAttribute *attr = (EVCardAttribute *) l->data;
+ gchar *raw;
+ CamelInternetAddress *addr;
+
+ if (!attr)
+ continue;
+
+ raw = e_vcard_attribute_get_value (attr);
+ if (!raw)
+ continue;
+
+ addr = camel_internet_address_new ();
+ if (camel_address_decode (CAMEL_ADDRESS (addr), raw) > 0) {
+ const gchar *nm = NULL, *eml = NULL;
+
+ camel_internet_address_get (addr, 0, &nm, &eml);
+ if (eml) {
+ /* keep both lists in sync */
+ if (member_values && g_hash_table_lookup (member_values, raw)) {
+ /* stored ListMembers values when contact's value didn't change */
+ members->lpbin[members->cValues].cb = string_to_bin (mem_ctx, g_hash_table_lookup (member_values, raw), &members->lpbin[members->cValues].lpb);
+ members->cValues++;
+ } else {
+ exchange_mapi_util_entryid_generate_oneoff (mem_ctx, &members->lpbin[members->cValues], nm ? nm : "", eml);
+ members->cValues++;
+ }
+
+ exchange_mapi_util_entryid_generate_oneoff (mem_ctx, &oneoff_members->lpbin[oneoff_members->cValues], nm ? nm : "", eml);
+ oneoff_members->cValues++;
+
+ list_size += MAX (oneoff_members->lpbin[oneoff_members->cValues - 1].cb, members->lpbin[members->cValues - 1].cb);
+ crc32 = exchange_mapi_utils_push_crc32 (crc32, members->lpbin[members->cValues - 1].lpb, members->lpbin[members->cValues - 1].cb);
+ }
+ }
+
+ g_object_unref (addr);
+ g_free (raw);
+ }
+
+ if (member_values)
+ g_hash_table_destroy (member_values);
+ if (member_ids)
+ g_hash_table_destroy (member_ids);
+ g_list_foreach (local, (GFunc)e_vcard_attribute_free, NULL);
+ g_list_free (local);
+
+ if (!exchange_mapi_utils_add_spropvalue_named_id (conn, fid, mem_ctx, values, n_values,
+ PidLidDistributionListOneOffMembers, oneoff_members))
+ return FALSE;
+
+ if (!exchange_mapi_utils_add_spropvalue_named_id (conn, fid, mem_ctx, values, n_values,
+ PidLidDistributionListMembers, members))
+ return FALSE;
+
+ if (!exchange_mapi_utils_add_spropvalue_named_id (conn, fid, mem_ctx, values, n_values,
+ PidLidDistributionListChecksum, &crc32))
+ return FALSE;
+
+ /* list_size shouldn't exceed 15000 bytes, is so, use a stream instead of those properties above, but for now... */
+ if (list_size > 15000)
+ return FALSE;
+
+ return TRUE;
+ }
+
+ set_str_value (PR_MESSAGE_CLASS, IPM_CONTACT);
+ set_str_named_con_value (PidLidFileUnder, E_CONTACT_FILE_AS);
+
+ set_str_con_value (PR_DISPLAY_NAME_UNICODE, E_CONTACT_FULL_NAME);
+ set_str_con_value (PR_NORMALIZED_SUBJECT_UNICODE, E_CONTACT_FILE_AS);
+ set_str_named_con_value (PidLidEmail1OriginalDisplayName, E_CONTACT_EMAIL_1);
+ /*set_str_named_con_value (PidLidEmail1EmailAddress, E_CONTACT_EMAIL_1);*/
+
+ /*set_str_con_value (0x8083001e, E_CONTACT_EMAIL_1);*/
+ set_str_named_con_value (PidLidEmail2EmailAddress, E_CONTACT_EMAIL_2);
+
+ set_str_named_con_value (PidLidEmail3EmailAddress, E_CONTACT_EMAIL_3);
+ /*set_str_named_con_value (PidLidEmail3OriginalDisplayName, E_CONTACT_EMAIL_3);*/
+
+ set_str_named_con_value (PidLidHtml, E_CONTACT_HOMEPAGE_URL);
+ set_str_named_con_value (PidLidFreeBusyLocation, E_CONTACT_FREEBUSY_URL);
+
+ set_str_con_value (PR_OFFICE_TELEPHONE_NUMBER_UNICODE, E_CONTACT_PHONE_BUSINESS);
+ set_str_con_value (PR_HOME_TELEPHONE_NUMBER_UNICODE, E_CONTACT_PHONE_HOME);
+ set_str_con_value (PR_MOBILE_TELEPHONE_NUMBER_UNICODE, E_CONTACT_PHONE_MOBILE);
+ set_str_con_value (PR_HOME_FAX_NUMBER_UNICODE, E_CONTACT_PHONE_HOME_FAX);
+ set_str_con_value (PR_BUSINESS_FAX_NUMBER_UNICODE, E_CONTACT_PHONE_BUSINESS_FAX);
+ set_str_con_value (PR_PAGER_TELEPHONE_NUMBER_UNICODE, E_CONTACT_PHONE_PAGER);
+ set_str_con_value (PR_ASSISTANT_TELEPHONE_NUMBER_UNICODE, E_CONTACT_PHONE_ASSISTANT);
+ set_str_con_value (PR_COMPANY_MAIN_PHONE_NUMBER_UNICODE, E_CONTACT_PHONE_COMPANY);
+
+ set_str_con_value (PR_MANAGER_NAME_UNICODE, E_CONTACT_MANAGER);
+ set_str_con_value (PR_ASSISTANT_UNICODE, E_CONTACT_ASSISTANT);
+ set_str_con_value (PR_COMPANY_NAME_UNICODE, E_CONTACT_ORG);
+ set_str_con_value (PR_DEPARTMENT_NAME_UNICODE, E_CONTACT_ORG_UNIT);
+ set_str_con_value (PR_PROFESSION_UNICODE, E_CONTACT_ROLE);
+ set_str_con_value (PR_TITLE_UNICODE, E_CONTACT_TITLE);
+
+ set_str_con_value (PR_OFFICE_LOCATION_UNICODE, E_CONTACT_OFFICE);
+ set_str_con_value (PR_SPOUSE_NAME_UNICODE, E_CONTACT_SPOUSE);
+
+ set_str_con_value (PR_BODY_UNICODE, E_CONTACT_NOTE);
+ set_str_con_value (PR_NICKNAME_UNICODE, E_CONTACT_NICKNAME);
+
+ /* BDAY AND ANNV */
+ if (e_contact_get (mcd->contact, E_CONTACT_BIRTH_DATE)) {
+ EContactDate *date = e_contact_get (mcd->contact, E_CONTACT_BIRTH_DATE);
+ struct tm tmtime;
+ time_t lt;
+ NTTIME nt;
+ struct FILETIME t;
+
+ tmtime.tm_mday = date->day;
+ tmtime.tm_mon = date->month - 1;
+ tmtime.tm_year = date->year - 1900;
+
+ lt = mktime (&tmtime);
+ unix_to_nt_time (&nt, lt);
+ t.dwLowDateTime = (nt << 32) >> 32;
+ t.dwHighDateTime = (nt >> 32);
+
+ if (!exchange_mapi_utils_add_spropvalue (mem_ctx, values, n_values, PR_BIRTHDAY, &t))
+ return FALSE;
+ }
+
+ if (e_contact_get (mcd->contact, E_CONTACT_ANNIVERSARY)) {
+ EContactDate *date = e_contact_get (mcd->contact, E_CONTACT_ANNIVERSARY);
+ struct tm tmtime;
+ time_t lt;
+ NTTIME nt;
+ struct FILETIME t;
+
+ tmtime.tm_mday = date->day;
+ tmtime.tm_mon = date->month - 1;
+ tmtime.tm_year = date->year - 1900;
+
+ lt = mktime (&tmtime);
+ unix_to_nt_time (&nt, lt);
+ t.dwLowDateTime = (nt << 32) >> 32;
+ t.dwHighDateTime = (nt >> 32);
+
+ if (!exchange_mapi_utils_add_spropvalue (mem_ctx, values, n_values, PR_WEDDING_ANNIVERSARY, &t))
+ return FALSE;
+ }
+
+ /* Home and Office address */
+ if (e_contact_get (mcd->contact, E_CONTACT_ADDRESS_HOME)) {
+ EContactAddress *contact_addr = e_contact_get (mcd->contact, E_CONTACT_ADDRESS_HOME);
+
+ set_str_named_value (PidLidHomeAddress, contact_addr->street);
+ set_str_value (PR_HOME_ADDRESS_POST_OFFICE_BOX_UNICODE, contact_addr->ext);
+ set_str_value (PR_HOME_ADDRESS_CITY_UNICODE, contact_addr->locality);
+ set_str_value (PR_HOME_ADDRESS_STATE_OR_PROVINCE_UNICODE, contact_addr->region);
+ set_str_value (PR_HOME_ADDRESS_POSTAL_CODE_UNICODE, contact_addr->code);
+ set_str_value (PR_HOME_ADDRESS_COUNTRY_UNICODE, contact_addr->country);
+ }
+
+ if (e_contact_get (mcd->contact, E_CONTACT_ADDRESS_WORK)) {
+ EContactAddress *contact_addr = e_contact_get (mcd->contact, E_CONTACT_ADDRESS_WORK);
+
+ set_str_named_value (PidLidWorkAddress, contact_addr->street);
+ set_str_value (PR_POST_OFFICE_BOX_UNICODE, contact_addr->ext);
+ set_str_value (PR_LOCALITY_UNICODE, contact_addr->locality);
+ set_str_value (PR_STATE_OR_PROVINCE_UNICODE, contact_addr->region);
+ set_str_value (PR_POSTAL_CODE_UNICODE, contact_addr->code);
+ set_str_value (PR_COUNTRY_UNICODE, contact_addr->country);
+ }
+
+ if (e_contact_get (mcd->contact, E_CONTACT_IM_AIM)) {
+ GList *l = e_contact_get (mcd->contact, E_CONTACT_IM_AIM);
+ set_str_named_value (PidLidInstantMessagingAddress, l->data);
+ }
+
+ return TRUE;
+}
+
+struct FetchContactItemData
+{
+ EBookBackendMAPI *ebma;
+ EContact *contact; /* out */
+};
+
+static gboolean
+fetch_contact_item_cb (FetchItemsCallbackData *item_data, gpointer data)
+{
+ struct FetchContactItemData *fcid = data;
+
+ g_return_val_if_fail (data != NULL, FALSE);
+ g_return_val_if_fail (fcid->ebma != NULL, FALSE);
+
+ fcid->contact = mapi_book_utils_contact_from_props (item_data->conn, item_data->fid, e_book_backend_mapi_get_book_uri (fcid->ebma), item_data->properties, NULL);
+
+ if (fcid->contact) {
+ gchar *suid = exchange_mapi_util_mapi_ids_to_uid (item_data->fid, item_data->mid);
+
+ /* UID of the contact is nothing but the concatenated string of hex id of folder and the message.*/
+ e_contact_set (fcid->contact, E_CONTACT_UID, suid);
+
+ if (!e_book_backend_mapi_notify_contact_update (fcid->ebma, NULL, fcid->contact, NULL, item_data->index, item_data->total, NULL)) {
+ g_free (suid);
+ return FALSE;
+ }
+
+ g_free (suid);
+ }
+
+ return TRUE;
+}
+
+struct CreateContactListData
+{
+ EBookBackendMAPI *ebma;
+ GList **vCards;
+};
+
+static gboolean
+create_contact_list_cb (FetchItemsCallbackData *item_data, gpointer data)
+{
+ struct CreateContactListData *ccld = data;
+ EContact *contact;
+
+ g_return_val_if_fail (data != NULL, FALSE);
+ g_return_val_if_fail (ccld->ebma != NULL, FALSE);
+ g_return_val_if_fail (ccld->vCards != NULL, FALSE);
+
+ contact = mapi_book_utils_contact_from_props (item_data->conn, item_data->fid, e_book_backend_mapi_get_book_uri (ccld->ebma), item_data->properties, NULL);
+ if (contact) {
+ gchar *suid = exchange_mapi_util_mapi_ids_to_uid (item_data->fid, item_data->mid);
+
+ e_contact_set (contact, E_CONTACT_UID, suid);
+
+ *ccld->vCards = g_list_prepend (*ccld->vCards, e_vcard_to_string (E_VCARD (contact), EVC_FORMAT_VCARD_30));
+
+ e_book_backend_mapi_notify_contact_update (ccld->ebma, NULL, contact, NULL, -1, -1, NULL);
+
+ g_object_unref (contact);
+ g_free (suid);
+ }
+
+ return TRUE;
+}
+
+struct FetchContactsData
+{
+ EBookBackendMAPI *ebma;
+ EDataBookView *book_view;
+ gpointer notify_contact_data;
+};
+
+static gboolean
+fetch_contacts_cb (FetchItemsCallbackData *item_data, gpointer data)
+{
+ struct FetchContactsData *fcd = data;
+ EContact *contact;
+
+ g_return_val_if_fail (data != NULL, FALSE);
+ g_return_val_if_fail (fcd->ebma != NULL, FALSE);
+ g_return_val_if_fail (fcd->ebma->priv != NULL, FALSE);
+
+ contact = mapi_book_utils_contact_from_props (item_data->conn, item_data->fid, e_book_backend_mapi_get_book_uri (fcd->ebma), item_data->properties, NULL);
+
+ if (contact) {
+ gchar *suid;
+ struct timeval *last_modification = NULL, tv = { 0 };
+
+ suid = exchange_mapi_util_mapi_ids_to_uid (item_data->fid, item_data->mid);
+ e_contact_set (contact, E_CONTACT_UID, suid);
+ g_free (suid);
+
+ if (get_mapi_SPropValue_array_date_timeval (&tv, item_data->properties, PR_LAST_MODIFICATION_TIME) == MAPI_E_SUCCESS)
+ last_modification = &tv;
+
+ if (!e_book_backend_mapi_notify_contact_update (fcd->ebma, fcd->book_view, contact, last_modification, item_data->index, item_data->total, fcd->notify_contact_data)) {
+ g_object_unref (contact);
+ return FALSE;
+ }
+
+ g_object_unref (contact);
+ }
+
+ return TRUE;
+}
+
+struct FetchContactsUidsData
+{
+ GCancellable *cancelled;
+ GHashTable *uids;
+};
+
+static gboolean
+fetch_contacts_uids_cb (FetchItemsCallbackData *item_data, gpointer data)
+{
+ struct FetchContactsUidsData *fcud = data;
+ gchar *suid;
+
+ g_return_val_if_fail (data != NULL, FALSE);
+
+ suid = exchange_mapi_util_mapi_ids_to_uid (item_data->fid, item_data->mid);
+ if (suid)
+ g_hash_table_insert (fcud->uids, suid, GINT_TO_POINTER (1));
+
+ return !g_cancellable_is_cancelled (fcud->cancelled);
+}
+
+static void
+ebbm_contacts_load_source (EBookBackendMAPI *ebma, ESource *source, gboolean only_if_exists, GError **perror)
+{
+ EBookBackendMAPIContactsPrivate *priv = ((EBookBackendMAPIContacts *) ebma)->priv;
+ GError *err = NULL;
+
+ if (e_book_backend_is_loaded (E_BOOK_BACKEND (ebma)))
+ return /* Success */;
+
+ priv->fid = 0;
+ priv->is_public_folder = e_source_get_property (source, "public") && g_str_equal (e_source_get_property (source, "public"), "yes");
+
+ exchange_mapi_util_mapi_id_from_string (e_source_get_property (source, "folder-id"), &priv->fid);
+
+ /* Chain up to parent's op_load_source() method. */
+ if (E_BOOK_BACKEND_MAPI_CLASS (e_book_backend_mapi_contacts_parent_class)->op_load_source)
+ E_BOOK_BACKEND_MAPI_CLASS (e_book_backend_mapi_contacts_parent_class)->op_load_source (ebma, source, only_if_exists, &err);
+
+ if (err)
+ g_propagate_error (perror, err);
+}
+
+static void
+ebbm_contacts_connection_status_changed (EBookBackendMAPI *ebma, gboolean is_online)
+{
+ e_book_backend_set_is_writable (E_BOOK_BACKEND (ebma), is_online);
+ e_book_backend_notify_writable (E_BOOK_BACKEND (ebma), is_online);
+}
+
+static void
+ebbm_contacts_remove (EBookBackendMAPI *ebma, GError **error)
+{
+ EBookBackendMAPIContactsPrivate *priv;
+ GError *mapi_error = NULL;
+
+ e_return_data_book_error_if_fail (ebma != NULL, E_DATA_BOOK_STATUS_INVALID_ARG);
+ e_return_data_book_error_if_fail (E_IS_BOOK_BACKEND_MAPI_CONTACTS (ebma), E_DATA_BOOK_STATUS_INVALID_ARG);
+
+ priv = E_BOOK_BACKEND_MAPI_CONTACTS (ebma)->priv;
+ e_return_data_book_error_if_fail (priv != NULL, E_DATA_BOOK_STATUS_INVALID_ARG);
+
+ if (E_BOOK_BACKEND_MAPI_GET_CLASS (ebma)->op_remove)
+ E_BOOK_BACKEND_MAPI_GET_CLASS (ebma)->op_remove (ebma, &mapi_error);
+
+ if (mapi_error) {
+ mapi_error_to_edb_error (error, mapi_error, E_DATA_BOOK_STATUS_OTHER_ERROR, NULL);
+ g_error_free (mapi_error);
+ return;
+ }
+
+ if (priv->is_public_folder) {
+ ExchangeMapiConnection *conn;
+
+ e_book_backend_mapi_lock_connection (ebma);
+
+ conn = e_book_backend_mapi_get_connection (ebma);
+ if (!conn) {
+ g_propagate_error (error, EDB_ERROR (OFFLINE_UNAVAILABLE));
+ } else {
+ exchange_mapi_connection_remove_folder (conn, priv->fid, MAPI_OPTIONS_USE_PFSTORE, &mapi_error);
+
+ if (mapi_error) {
+ mapi_error_to_edb_error (error, mapi_error, E_DATA_BOOK_STATUS_OTHER_ERROR, _("Failed to remove public folder"));
+ g_error_free (mapi_error);
+ }
+ }
+
+ e_book_backend_mapi_unlock_connection (ebma);
+ }
+}
+
+static void
+ebbm_contacts_create_contact (EBookBackendMAPI *ebma, const gchar *vcard, EContact **contact, GError **error)
+{
+ EBookBackendMAPIContacts *ebmac;
+ EBookBackendMAPIContactsPrivate *priv;
+ ExchangeMapiConnection *conn;
+ MapiCreateitemData mcd;
+ GError *mapi_error = NULL;
+ mapi_id_t mid;
+ gchar *id;
+
+ e_return_data_book_error_if_fail (ebma != NULL, E_DATA_BOOK_STATUS_INVALID_ARG);
+ e_return_data_book_error_if_fail (E_IS_BOOK_BACKEND_MAPI_CONTACTS (ebma), E_DATA_BOOK_STATUS_INVALID_ARG);
+ e_return_data_book_error_if_fail (vcard != NULL, E_DATA_BOOK_STATUS_INVALID_ARG);
+ e_return_data_book_error_if_fail (contact != NULL, E_DATA_BOOK_STATUS_INVALID_ARG);
+
+ ebmac = E_BOOK_BACKEND_MAPI_CONTACTS (ebma);
+ e_return_data_book_error_if_fail (ebmac != NULL, E_DATA_BOOK_STATUS_INVALID_ARG);
+
+ priv = ebmac->priv;
+ e_return_data_book_error_if_fail (priv != NULL, E_DATA_BOOK_STATUS_INVALID_ARG);
+
+ e_book_backend_mapi_lock_connection (ebma);
+
+ conn = e_book_backend_mapi_get_connection (ebma);
+ if (!conn) {
+ g_propagate_error (error, EDB_ERROR (REPOSITORY_OFFLINE));
+ e_book_backend_mapi_unlock_connection (ebma);
+ return;
+ }
+
+ *contact = e_contact_new_from_vcard (vcard);
+ if (!*contact) {
+ g_propagate_error (error, EDB_ERROR (REPOSITORY_OFFLINE));
+ e_book_backend_mapi_unlock_connection (ebma);
+ return;
+ }
+
+ e_book_backend_mapi_get_summary_and_cache (ebma, NULL, &mcd.cache);
+ mcd.contact = *contact;
+
+ mid = exchange_mapi_connection_create_item (conn, olFolderContacts, priv->fid,
+ mapi_book_write_props, &mcd,
+ NULL, NULL, NULL, priv->is_public_folder ? MAPI_OPTIONS_USE_PFSTORE : 0, &mapi_error);
+
+ e_book_backend_mapi_unlock_connection (ebma);
+
+ if (!mid) {
+ mapi_error_to_edb_error (error, mapi_error, E_DATA_BOOK_STATUS_OTHER_ERROR, _("Failed to create item on a server"));
+
+ if (mapi_error)
+ g_error_free (mapi_error);
+
+ g_object_unref (*contact);
+ *contact = NULL;
+ return;
+ }
+
+ id = exchange_mapi_util_mapi_ids_to_uid (priv->fid, mid);
+
+ /* UID of the contact is nothing but the concatenated string of hex id of folder and the message.*/
+ e_contact_set (*contact, E_CONTACT_UID, id);
+ e_contact_set (*contact, E_CONTACT_BOOK_URI, e_book_backend_mapi_get_book_uri (ebma));
+
+ g_free (id);
+}
+
+static void
+ebbm_contacts_remove_contacts (EBookBackendMAPI *ebma, const GList *id_list, GList **removed_ids, GError **error)
+{
+ EBookBackendMAPIContacts *ebmac;
+ EBookBackendMAPIContactsPrivate *priv;
+ ExchangeMapiConnection *conn;
+ GError *mapi_error = NULL;
+ GSList *to_remove;
+ const GList *l;
+
+ e_return_data_book_error_if_fail (ebma != NULL, E_DATA_BOOK_STATUS_INVALID_ARG);
+ e_return_data_book_error_if_fail (E_IS_BOOK_BACKEND_MAPI_CONTACTS (ebma), E_DATA_BOOK_STATUS_INVALID_ARG);
+ e_return_data_book_error_if_fail (id_list != NULL, E_DATA_BOOK_STATUS_INVALID_ARG);
+ e_return_data_book_error_if_fail (removed_ids != NULL, E_DATA_BOOK_STATUS_INVALID_ARG);
+
+ ebmac = E_BOOK_BACKEND_MAPI_CONTACTS (ebma);
+ e_return_data_book_error_if_fail (ebmac != NULL, E_DATA_BOOK_STATUS_INVALID_ARG);
+
+ priv = ebmac->priv;
+ e_return_data_book_error_if_fail (priv != NULL, E_DATA_BOOK_STATUS_INVALID_ARG);
+
+ e_book_backend_mapi_lock_connection (ebma);
+
+ conn = e_book_backend_mapi_get_connection (ebma);
+ if (!conn) {
+ g_propagate_error (error, EDB_ERROR (REPOSITORY_OFFLINE));
+ e_book_backend_mapi_unlock_connection (ebma);
+ return;
+ }
+
+ to_remove = NULL;
+ for (l = id_list; l; l = l->next) {
+ mapi_id_t mid, fid;
+ const gchar *uid = l->data;
+ struct id_list *idl = g_new0 (struct id_list, 1);
+
+ exchange_mapi_util_mapi_ids_from_uid (uid, &fid, &mid);
+
+ idl->id = mid;
+ to_remove = g_slist_prepend (to_remove, idl);
+
+ *removed_ids = g_list_prepend (*removed_ids, g_strdup (uid));
+ }
+
+ exchange_mapi_connection_remove_items (conn, olFolderContacts, priv->fid, priv->is_public_folder ? MAPI_OPTIONS_USE_PFSTORE : 0, to_remove, &mapi_error);
+
+ e_book_backend_mapi_unlock_connection (ebma);
+
+ if (mapi_error) {
+ mapi_error_to_edb_error (error, mapi_error, E_DATA_BOOK_STATUS_OTHER_ERROR, NULL);
+
+ g_error_free (mapi_error);
+
+ g_list_foreach (*removed_ids, (GFunc) g_free, NULL);
+ g_list_free (*removed_ids);
+ *removed_ids = NULL;
+ }
+
+ g_slist_foreach (to_remove, (GFunc) g_free, NULL);
+ g_slist_free (to_remove);
+}
+
+static void
+ebbm_contacts_modify_contact (EBookBackendMAPI *ebma, const gchar *vcard, EContact **contact, GError **error)
+{
+ EBookBackendMAPIContacts *ebmac;
+ EBookBackendMAPIContactsPrivate *priv;
+ ExchangeMapiConnection *conn;
+ MapiCreateitemData mcd;
+ GError *mapi_error = NULL;
+ mapi_id_t fid, mid;
+
+ e_return_data_book_error_if_fail (ebma != NULL, E_DATA_BOOK_STATUS_INVALID_ARG);
+ e_return_data_book_error_if_fail (E_IS_BOOK_BACKEND_MAPI_CONTACTS (ebma), E_DATA_BOOK_STATUS_INVALID_ARG);
+ e_return_data_book_error_if_fail (vcard != NULL, E_DATA_BOOK_STATUS_INVALID_ARG);
+ e_return_data_book_error_if_fail (contact != NULL, E_DATA_BOOK_STATUS_INVALID_ARG);
+
+ ebmac = E_BOOK_BACKEND_MAPI_CONTACTS (ebma);
+ e_return_data_book_error_if_fail (ebmac != NULL, E_DATA_BOOK_STATUS_INVALID_ARG);
+
+ priv = ebmac->priv;
+ e_return_data_book_error_if_fail (priv != NULL, E_DATA_BOOK_STATUS_INVALID_ARG);
+
+ e_book_backend_mapi_lock_connection (ebma);
+
+ conn = e_book_backend_mapi_get_connection (ebma);
+ if (!conn) {
+ g_propagate_error (error, EDB_ERROR (REPOSITORY_OFFLINE));
+ e_book_backend_mapi_unlock_connection (ebma);
+ return;
+ }
+
+ *contact = e_contact_new_from_vcard (vcard);
+ if (!*contact) {
+ g_propagate_error (error, EDB_ERROR (REPOSITORY_OFFLINE));
+ e_book_backend_mapi_unlock_connection (ebma);
+ return;
+ }
+
+ e_book_backend_mapi_get_summary_and_cache (ebma, NULL, &mcd.cache);
+ mcd.contact = *contact;
+
+ exchange_mapi_util_mapi_ids_from_uid (e_contact_get_const (*contact, E_CONTACT_UID), &fid, &mid);
+
+ if (!exchange_mapi_connection_modify_item (conn, olFolderContacts, priv->fid, mid,
+ mapi_book_write_props, &mcd, NULL, NULL, NULL, priv->is_public_folder ? MAPI_OPTIONS_USE_PFSTORE : 0, &mapi_error)) {
+
+ mapi_error_to_edb_error (error, mapi_error, E_DATA_BOOK_STATUS_OTHER_ERROR, _("Failed to modify item on a server"));
+ if (mapi_error)
+ g_error_free (mapi_error);
+
+ g_object_unref (*contact);
+ *contact = NULL;
+ }
+
+ e_book_backend_mapi_unlock_connection (ebma);
+}
+
+static void
+ebbm_contacts_get_contact (EBookBackendMAPI *ebma, const gchar *id, gchar **vcard, GError **error)
+{
+ EBookBackendMAPIContacts *ebmac;
+ EBookBackendMAPIContactsPrivate *priv;
+ ExchangeMapiConnection *conn;
+ mapi_id_t fid, mid;
+ guint32 options;
+ struct FetchContactItemData fcid = { 0 };
+ GError *mapi_error = NULL;
+
+ e_return_data_book_error_if_fail (ebma != NULL, E_DATA_BOOK_STATUS_INVALID_ARG);
+ e_return_data_book_error_if_fail (E_IS_BOOK_BACKEND_MAPI_CONTACTS (ebma), E_DATA_BOOK_STATUS_INVALID_ARG);
+ e_return_data_book_error_if_fail (id != NULL, E_DATA_BOOK_STATUS_INVALID_ARG);
+ e_return_data_book_error_if_fail (vcard != NULL, E_DATA_BOOK_STATUS_INVALID_ARG);
+
+ ebmac = E_BOOK_BACKEND_MAPI_CONTACTS (ebma);
+ e_return_data_book_error_if_fail (ebmac != NULL, E_DATA_BOOK_STATUS_INVALID_ARG);
+
+ priv = ebmac->priv;
+ e_return_data_book_error_if_fail (priv != NULL, E_DATA_BOOK_STATUS_INVALID_ARG);
+
+ if (E_BOOK_BACKEND_MAPI_CLASS (e_book_backend_mapi_contacts_parent_class)->op_get_contact)
+ E_BOOK_BACKEND_MAPI_CLASS (e_book_backend_mapi_contacts_parent_class)->op_get_contact (ebma, id, vcard, &mapi_error);
+
+ if (mapi_error) {
+ g_propagate_error (error, mapi_error);
+ return;
+ }
+
+ /* found in a cache */
+ if (*vcard)
+ return;
+
+ e_book_backend_mapi_lock_connection (ebma);
+
+ conn = e_book_backend_mapi_get_connection (ebma);
+ if (!conn) {
+ g_propagate_error (error, EDB_ERROR (REPOSITORY_OFFLINE));
+ e_book_backend_mapi_unlock_connection (ebma);
+ return;
+ }
+
+ options = MAPI_OPTIONS_FETCH_ALL;
+ if (priv->is_public_folder)
+ options |= MAPI_OPTIONS_USE_PFSTORE;
+
+ fcid.ebma = ebma;
+ fcid.contact = NULL;
+ exchange_mapi_util_mapi_ids_from_uid (id, &fid, &mid);
+
+ exchange_mapi_connection_fetch_item (conn, priv->fid, mid,
+ priv->is_public_folder ? NULL : mapi_book_utils_get_prop_list, GET_ALL_KNOWN_IDS,
+ fetch_contact_item_cb, &fcid,
+ options, &mapi_error);
+
+ if (fcid.contact) {
+ *vcard = e_vcard_to_string (E_VCARD (fcid.contact), EVC_FORMAT_VCARD_30);
+ g_object_unref (fcid.contact);
+ } else {
+ if (!mapi_error || mapi_error->code == MAPI_E_NOT_FOUND) {
+ g_propagate_error (error, EDB_ERROR (CONTACT_NOT_FOUND));
+ } else {
+ mapi_error_to_edb_error (error, mapi_error, E_DATA_BOOK_STATUS_CONTACT_NOT_FOUND, NULL);
+ }
+
+ if (mapi_error)
+ g_error_free (mapi_error);
+ }
+
+ e_book_backend_mapi_unlock_connection (ebma);
+}
+
+static void
+ebbm_contacts_get_contact_list (EBookBackendMAPI *ebma, const gchar *query, GList **vCards, GError **error)
+{
+ EBookBackendMAPIContacts *ebmac;
+ EBookBackendMAPIContactsPrivate *priv;
+ ExchangeMapiConnection *conn;
+ guint32 options;
+ struct CreateContactListData ccld = { 0 };
+ GError *mapi_error = NULL;
+ struct mapi_SRestriction res;
+ gboolean get_all;
+
+ e_return_data_book_error_if_fail (ebma != NULL, E_DATA_BOOK_STATUS_INVALID_ARG);
+ e_return_data_book_error_if_fail (E_IS_BOOK_BACKEND_MAPI_CONTACTS (ebma), E_DATA_BOOK_STATUS_INVALID_ARG);
+ e_return_data_book_error_if_fail (query != NULL, E_DATA_BOOK_STATUS_INVALID_ARG);
+ e_return_data_book_error_if_fail (vCards != NULL, E_DATA_BOOK_STATUS_INVALID_ARG);
+
+ ebmac = E_BOOK_BACKEND_MAPI_CONTACTS (ebma);
+ e_return_data_book_error_if_fail (ebmac != NULL, E_DATA_BOOK_STATUS_INVALID_ARG);
+
+ priv = ebmac->priv;
+ e_return_data_book_error_if_fail (priv != NULL, E_DATA_BOOK_STATUS_INVALID_ARG);
+
+ if (E_BOOK_BACKEND_MAPI_CLASS (e_book_backend_mapi_contacts_parent_class)->op_get_contact_list)
+ E_BOOK_BACKEND_MAPI_CLASS (e_book_backend_mapi_contacts_parent_class)->op_get_contact_list (ebma, query, vCards, &mapi_error);
+
+ if (mapi_error) {
+ g_propagate_error (error, mapi_error);
+ return;
+ }
+
+ /* found some in cache, thus use them */
+ if (*vCards)
+ return;
+
+ options = MAPI_OPTIONS_FETCH_ALL;
+ if (priv->is_public_folder)
+ options |= MAPI_OPTIONS_USE_PFSTORE;
+
+ e_book_backend_mapi_lock_connection (ebma);
+
+ conn = e_book_backend_mapi_get_connection (ebma);
+ if (!conn) {
+ e_book_backend_mapi_unlock_connection (ebma);
+ g_propagate_error (error, EDB_ERROR (REPOSITORY_OFFLINE));
+
+ return;
+ }
+
+ ccld.ebma = ebma;
+ ccld.vCards = vCards;
+
+ get_all = g_ascii_strcasecmp (query, "(contains \"x-evolution-any-field\" \"\")") == 0;
+ if (!get_all && !build_restriction_emails_contains (&res, query)) {
+ e_book_backend_mapi_unlock_connection (ebma);
+ g_propagate_error (error, EDB_ERROR (OTHER_ERROR));
+
+ return;
+ }
+
+ if (!exchange_mapi_connection_fetch_items (conn, priv->fid, get_all ? NULL : &res, NULL,
+ priv->is_public_folder ? NULL : mapi_book_utils_get_prop_list, GET_ALL_KNOWN_IDS,
+ create_contact_list_cb, &ccld, options, &mapi_error)) {
+ mapi_error_to_edb_error (error, mapi_error, E_DATA_BOOK_STATUS_OTHER_ERROR, _("Failed to fetch items from a server"));
+ if (mapi_error)
+ g_error_free (mapi_error);
+ }
+
+ e_book_backend_mapi_unlock_connection (ebma);
+}
+
+static gchar *
+ebbm_contacts_get_status_message (EBookBackendMAPI *ebma, gint index, gint total)
+{
+ if (index <= 0)
+ return NULL;
+
+ return g_strdup_printf (
+ total <= 0 ?
+ /* Translators : This is used to cache the downloaded contacts from a server.
+ %d is an index of the contact. */
+ _("Caching contact %d") :
+ /* Translators : This is used to cache the downloaded contacts from a server.
+ The first %d is an index of the contact,
+ the second %d is total count of conacts on the server. */
+ _("Caching contact %d/%d"),
+ index, total);
+}
+
+static void
+ebbm_contacts_fetch_contacts (EBookBackendMAPI *ebma, struct mapi_SRestriction *restriction, EDataBookView *book_view, gpointer notify_contact_data, GError **error)
+{
+ EBookBackendMAPIContacts *ebmac;
+ EBookBackendMAPIContactsPrivate *priv;
+ ExchangeMapiConnection *conn;
+ guint32 options;
+ struct FetchContactsData fcd = { 0 };
+ GError *mapi_error = NULL;
+
+ e_return_data_book_error_if_fail (ebma != NULL, E_DATA_BOOK_STATUS_INVALID_ARG);
+ e_return_data_book_error_if_fail (E_IS_BOOK_BACKEND_MAPI_CONTACTS (ebma), E_DATA_BOOK_STATUS_INVALID_ARG);
+
+ ebmac = E_BOOK_BACKEND_MAPI_CONTACTS (ebma);
+ e_return_data_book_error_if_fail (ebmac != NULL, E_DATA_BOOK_STATUS_INVALID_ARG);
+
+ priv = ebmac->priv;
+ e_return_data_book_error_if_fail (priv != NULL, E_DATA_BOOK_STATUS_INVALID_ARG);
+
+ e_book_backend_mapi_lock_connection (ebma);
+
+ conn = e_book_backend_mapi_get_connection (ebma);
+ if (!conn) {
+ e_book_backend_mapi_unlock_connection (ebma);
+ g_propagate_error (error, EDB_ERROR (REPOSITORY_OFFLINE));
+
+ return;
+ }
+
+ fcd.ebma = ebma;
+ fcd.book_view = book_view;
+ fcd.notify_contact_data = notify_contact_data;
+
+ options = MAPI_OPTIONS_FETCH_ALL;
+ if (priv->is_public_folder)
+ options |= MAPI_OPTIONS_USE_PFSTORE;
+
+ if (!exchange_mapi_connection_fetch_items (conn, priv->fid, restriction, NULL,
+ mapi_book_utils_get_prop_list, GET_ALL_KNOWN_IDS,
+ fetch_contacts_cb, &fcd, options, &mapi_error)) {
+ mapi_error_to_edb_error (error, mapi_error, E_DATA_BOOK_STATUS_OTHER_ERROR, _("Failed to fetch items from a server"));
+
+ if (mapi_error)
+ g_error_free (mapi_error);
+ }
+
+ e_book_backend_mapi_unlock_connection (ebma);
+}
+
+static void
+ebbm_contacts_fetch_known_uids (EBookBackendMAPI *ebma, GCancellable *cancelled, GHashTable *uids, GError **error)
+{
+ EBookBackendMAPIContacts *ebmac;
+ EBookBackendMAPIContactsPrivate *priv;
+ ExchangeMapiConnection *conn;
+ GError *mapi_error = NULL;
+ struct FetchContactsUidsData fcud = { 0 };
+ guint32 options;
+
+ e_return_data_book_error_if_fail (ebma != NULL, E_DATA_BOOK_STATUS_INVALID_ARG);
+ e_return_data_book_error_if_fail (E_IS_BOOK_BACKEND_MAPI_CONTACTS (ebma), E_DATA_BOOK_STATUS_INVALID_ARG);
+ e_return_data_book_error_if_fail (cancelled != NULL, E_DATA_BOOK_STATUS_INVALID_ARG);
+ e_return_data_book_error_if_fail (uids != NULL, E_DATA_BOOK_STATUS_INVALID_ARG);
+
+ ebmac = E_BOOK_BACKEND_MAPI_CONTACTS (ebma);
+ e_return_data_book_error_if_fail (ebmac != NULL, E_DATA_BOOK_STATUS_INVALID_ARG);
+ e_return_data_book_error_if_fail (ebmac->priv != NULL, E_DATA_BOOK_STATUS_INVALID_ARG);
+
+ priv = ebmac->priv;
+
+ e_book_backend_mapi_lock_connection (ebma);
+
+ conn = e_book_backend_mapi_get_connection (ebma);
+ if (!conn) {
+ e_book_backend_mapi_unlock_connection (ebma);
+ g_propagate_error (error, EDB_ERROR (REPOSITORY_OFFLINE));
+ return;
+ }
+
+ options = MAPI_OPTIONS_DONT_OPEN_MESSAGE;
+ if (priv->is_public_folder)
+ options |= MAPI_OPTIONS_USE_PFSTORE;
+
+ fcud.cancelled = cancelled;
+ fcud.uids = uids;
+
+ exchange_mapi_connection_fetch_items (conn, priv->fid, NULL, NULL,
+ mapi_book_utils_get_prop_list, GET_UIDS_ONLY,
+ fetch_contacts_uids_cb, &fcud, options, &mapi_error);
+
+ if (mapi_error) {
+ mapi_error_to_edb_error (error, mapi_error, E_DATA_BOOK_STATUS_OTHER_ERROR, _("Failed to fetch items from a server"));
+ g_error_free (mapi_error);
+ }
+
+ e_book_backend_mapi_unlock_connection (ebma);
+}
+
+static void
+e_book_backend_mapi_contacts_init (EBookBackendMAPIContacts *backend)
+{
+ backend->priv = G_TYPE_INSTANCE_GET_PRIVATE (backend, E_TYPE_BOOK_BACKEND_MAPI_CONTACTS, EBookBackendMAPIContactsPrivate);
+}
+
+static void
+e_book_backend_mapi_contacts_class_init (EBookBackendMAPIContactsClass *klass)
+{
+ EBookBackendMAPIClass *parent_class;
+
+ g_type_class_add_private (klass, sizeof (EBookBackendMAPIContactsPrivate));
+
+ parent_class = E_BOOK_BACKEND_MAPI_CLASS (klass);
+
+ /* Set the virtual methods. */
+ parent_class->op_load_source = ebbm_contacts_load_source;
+ parent_class->op_remove = ebbm_contacts_remove;
+ parent_class->op_create_contact = ebbm_contacts_create_contact;
+ parent_class->op_remove_contacts = ebbm_contacts_remove_contacts;
+ parent_class->op_modify_contact = ebbm_contacts_modify_contact;
+ parent_class->op_get_contact = ebbm_contacts_get_contact;
+ parent_class->op_get_contact_list = ebbm_contacts_get_contact_list;
+
+ parent_class->op_connection_status_changed = ebbm_contacts_connection_status_changed;
+ parent_class->op_get_status_message = ebbm_contacts_get_status_message;
+ parent_class->op_fetch_contacts = ebbm_contacts_fetch_contacts;
+ parent_class->op_fetch_known_uids = ebbm_contacts_fetch_known_uids;
+}
+
+EBookBackend *
+e_book_backend_mapi_contacts_new (void)
+{
+ return g_object_new (E_TYPE_BOOK_BACKEND_MAPI_CONTACTS, NULL);
+}
diff --git a/src/addressbook/e-book-backend-mapi-contacts.h b/src/addressbook/e-book-backend-mapi-contacts.h
new file mode 100644
index 0000000..c09723c
--- /dev/null
+++ b/src/addressbook/e-book-backend-mapi-contacts.h
@@ -0,0 +1,56 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
+/*
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) version 3.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with the program; if not, see <http://www.gnu.org/licenses/>
+ *
+ *
+ * Authors:
+ * Srinivasa Ragavan <sragavan novell com>
+ *
+ * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com)
+ *
+ */
+
+#ifndef __E_BOOK_BACKEND_MAPI_CONTACTS_H__
+#define __E_BOOK_BACKEND_MAPI_CONTACTS_H__
+
+#include "e-book-backend-mapi.h"
+
+G_BEGIN_DECLS
+
+#define E_TYPE_BOOK_BACKEND_MAPI_CONTACTS (e_book_backend_mapi_contacts_get_type ())
+#define E_BOOK_BACKEND_MAPI_CONTACTS(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), E_TYPE_BOOK_BACKEND_MAPI_CONTACTS, EBookBackendMAPIContacts))
+#define E_BOOK_BACKEND_MAPI_CONTACTS_CLASS(k) (G_TYPE_CHECK_CLASS_CAST((k), E_TYPE_BOOK_BACKEND_MAPI_CONTACTS, EBookBackendMAPIContactsClass))
+#define E_IS_BOOK_BACKEND_MAPI_CONTACTS(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), E_TYPE_BOOK_BACKEND_MAPI_CONTACTS))
+#define E_IS_BOOK_BACKEND_MAPI_CONTACTS_CLASS(k) (G_TYPE_CHECK_CLASS_TYPE ((k), E_TYPE_BOOK_BACKEND_MAPI_CONTACTS))
+#define E_BOOK_BACKEND_MAPI_CONTACTS_GET_CLASS(k) (G_TYPE_INSTANCE_GET_CLASS ((obj), E_TYPE_BOOK_BACKEND_MAPI_CONTACTS, EBookBackendMAPIContactsClass))
+
+typedef struct _EBookBackendMAPIContactsPrivate EBookBackendMAPIContactsPrivate;
+
+typedef struct
+{
+ EBookBackendMAPI parent_object;
+ EBookBackendMAPIContactsPrivate *priv;
+} EBookBackendMAPIContacts;
+
+typedef struct
+{
+ EBookBackendMAPIClass parent_class;
+} EBookBackendMAPIContactsClass;
+
+EBookBackend *e_book_backend_mapi_contacts_new (void);
+GType e_book_backend_mapi_contacts_get_type (void);
+
+G_END_DECLS
+
+#endif /* __E_BOOK_BACKEND_MAPI_CONTACTS_H__ */
diff --git a/src/addressbook/e-book-backend-mapi-factory.c b/src/addressbook/e-book-backend-mapi-factory.c
index b7f4eca..18fec2c 100644
--- a/src/addressbook/e-book-backend-mapi-factory.c
+++ b/src/addressbook/e-book-backend-mapi-factory.c
@@ -27,25 +27,30 @@
#include <libebackend/e-data-server-module.h>
#include <libedata-book/e-book-backend-factory.h>
-#include "e-book-backend-mapi.h"
-E_BOOK_BACKEND_FACTORY_SIMPLE (mapi,
- MAPI,
- e_book_backend_mapi_new)
+#include "e-book-backend-mapi-contacts.h"
+#include "e-book-backend-mapi-gal.h"
-static GType mapi_type;
+E_BOOK_BACKEND_FACTORY_SIMPLE (mapi, MAPI, e_book_backend_mapi_contacts_new)
+E_BOOK_BACKEND_FACTORY_SIMPLE (mapigal, MAPIGAL, e_book_backend_mapi_gal_new)
-void eds_module_initialize (GTypeModule *module)
+static GType mapi_type[2];
+
+void
+eds_module_initialize (GTypeModule *module)
{
- mapi_type = _mapi_factory_get_type (module);
+ mapi_type[0] = _mapi_factory_get_type (module);
+ mapi_type[1] = _mapigal_factory_get_type (module);
}
-void eds_module_shutdown (void)
+void
+eds_module_shutdown (void)
{
}
-void eds_module_list_types (const GType **types, gint *num_types)
+void
+eds_module_list_types (const GType **types, gint *num_types)
{
- *types = &mapi_type;
- *num_types = 1;
+ *types = mapi_type;
+ *num_types = G_N_ELEMENTS (mapi_type);
}
diff --git a/src/addressbook/e-book-backend-mapi-gal.c b/src/addressbook/e-book-backend-mapi-gal.c
index b514e4d..b85a439 100644
--- a/src/addressbook/e-book-backend-mapi-gal.c
+++ b/src/addressbook/e-book-backend-mapi-gal.c
@@ -22,160 +22,50 @@
#include <libedata-book/e-book-backend-summary.h>
#include "e-book-backend-mapi-gal.h"
-#include "e-book-backend-mapi-utils.h"
-G_DEFINE_TYPE (EBookBackendMAPIGAL, e_book_backend_mapi_gal, E_TYPE_BOOK_BACKEND)
-
-static gboolean enable_debug = TRUE;
+G_DEFINE_TYPE (EBookBackendMAPIGAL, e_book_backend_mapi_gal, E_TYPE_BOOK_BACKEND_MAPI)
struct _EBookBackendMAPIGALPrivate
{
- gchar *profile;
- ExchangeMapiConnection *conn;
+ /* nothing to store locally at the moment,
+ but keep it ready for any later need */
- mapi_id_t fid;
- gint mode;
- gboolean marked_for_offline;
- GThread *build_cache_thread;
- gboolean kill_cache_build;
- gboolean is_cache_ready;
- gboolean is_summary_ready;
- gboolean is_writable;
- gchar *uri;
-
- GMutex *lock;
- gchar *summary_file_name;
- EBookBackendSummary *summary;
- EBookBackendCache *cache;
-
- GStaticMutex running_mutex;
- GHashTable *view_to_closure_hash; /* EDataBookView -> BESearchClosure */
+ gint32 unused;
};
-#define SUMMARY_FLUSH_TIMEOUT 5000
-
-static gchar *
-e_book_backend_mapi_gal_get_static_capabilities (EBookBackend *backend)
-{
- if (enable_debug)
- printf("mapi get_static_capabilities\n");
- //FIXME: Implement this.
-
- return g_strdup ("net,bulk-removes,do-initial-query,contact-lists");
-}
-
-static EDataBookView *
-find_book_view (EBookBackendMAPIGAL *ebmapi)
-{
- EList *views = e_book_backend_get_book_views (E_BOOK_BACKEND (ebmapi));
- EIterator *iter;
- EDataBookView *rv = NULL;
- gint test;
-
- if (!views)
- return NULL;
-
- test = e_list_length (views);
-
- iter = e_list_get_iterator (views);
-
- if (!iter) {
- g_object_unref (views);
- return NULL;
- }
-
- if (e_iterator_is_valid (iter)) {
- /* just always use the first book view */
- EDataBookView *v = (EDataBookView*)e_iterator_get(iter);
- if (v)
- rv = v;
- }
-
- g_object_unref (iter);
- g_object_unref (views);
-
- return rv;
-}
-
-static void
-book_view_notify_status (EDataBookView *view, const gchar *status)
+struct FetchGalData
{
- if (!view)
- return;
- e_data_book_view_notify_status_message (view, status);
-}
-
-static guint32
-current_time_ms (void)
-{
- GTimeVal tv;
-
- g_get_current_time (&tv);
-
- return tv.tv_sec * 1000 + tv.tv_usec / 1000;
-}
-
-struct fetch_gal_data
-{
- EBookBackendMAPIGAL *ebmapi;
+ EBookBackendMAPI *ebma;
EDataBookView *book_view;
+ gpointer notify_contact_data;
mapi_id_t fid; /* folder ID of contacts, for named IDs */
- guint32 last_update; /* when in micro-seconds was done last notification about progress */
};
static gboolean
fetch_gal_cb (ExchangeMapiConnection *conn, uint32_t row_index, uint32_t n_rows, struct SRow *aRow, gpointer data)
{
- EBookBackendMAPIGALPrivate *priv;
- struct fetch_gal_data *fgd = data;
+ struct FetchGalData *fgd = data;
+ struct timeval *last_modification = NULL, tv = { 0 };
+ struct SPropValue *spropval;
EContact *contact;
- gchar *uid;
- guint32 current_time;
g_return_val_if_fail (conn != NULL, FALSE);
g_return_val_if_fail (aRow != NULL, FALSE);
g_return_val_if_fail (data != NULL, FALSE);
- priv = fgd->ebmapi->priv;
- if (priv->kill_cache_build)
- return FALSE;
-
- contact = mapi_book_utils_contact_from_props (conn, fgd->fid, NULL, aRow);
+ contact = mapi_book_utils_contact_from_props (conn, fgd->fid, e_book_backend_mapi_get_book_uri (fgd->ebma), NULL, aRow);
if (!contact) {
/* just ignore them */
return TRUE;
}
- uid = g_strdup_printf ("%d", row_index);
- e_contact_set (contact, E_CONTACT_UID, uid);
- g_free (uid);
-
- e_book_backend_cache_add_contact (priv->cache, contact);
- e_book_backend_summary_add_contact (priv->summary, contact);
-
- if (!fgd->book_view)
- fgd->book_view = find_book_view (fgd->ebmapi);
+ spropval = get_SPropValue_SRow (aRow, PR_LAST_MODIFICATION_TIME);
+ if (spropval && get_mapi_SPropValue_date_timeval (&tv, *spropval) == MAPI_E_SUCCESS)
+ last_modification = &tv;
- if (fgd->book_view)
- e_data_book_view_notify_update (fgd->book_view, contact);
-
- current_time = current_time_ms ();
- if (fgd->book_view && current_time - fgd->last_update >= 333) {
- gchar *status_msg;
-
- if (n_rows > 0) {
- /* To translators : This is used to cache the downloaded contacts from GAL.
- The first %d is an index of the GAL entry,
- the second %d is total count of entries in GAL. */
- status_msg = g_strdup_printf (_("Caching GAL entry %d/%d"), row_index, n_rows);
- } else {
- /* To translators : This is used to cache the downloaded contacts from GAL.
- %d is an index of the GAL entry. */
- status_msg = g_strdup_printf (_("Caching GAL entry %d"), row_index);
- }
- book_view_notify_status (fgd->book_view, status_msg);
- g_free (status_msg);
- fgd->last_update = current_time;
+ if (!e_book_backend_mapi_notify_contact_update (fgd->ebma, fgd->book_view, contact, last_modification, row_index, n_rows, fgd->notify_contact_data)) {
+ g_object_unref (contact);
+ return FALSE;
}
g_object_unref (contact);
@@ -183,736 +73,157 @@ fetch_gal_cb (ExchangeMapiConnection *conn, uint32_t row_index, uint32_t n_rows,
return TRUE;
}
-static gpointer
-build_cache (EBookBackendMAPIGAL *ebmapi)
+struct FetchGalUidsData
{
- EBookBackendMAPIGALPrivate *priv = ebmapi->priv;
- GError *mapi_error = NULL;
- gchar *tmp;
- struct fetch_gal_data fgd = { 0 };
-
- //FIXME: What if book view is NULL? Can it be? Check that.
- if (!priv->cache) {
- printf("Caching for the first time\n");
- priv->cache = e_book_backend_cache_new (priv->uri);
- }
-
- fgd.ebmapi = ebmapi;
- fgd.book_view = find_book_view (ebmapi);
- fgd.fid = exchange_mapi_connection_get_default_folder_id (priv->conn, olFolderContacts, NULL);
- fgd.last_update = current_time_ms ();
-
- e_file_cache_freeze_changes (E_FILE_CACHE (priv->cache));
- exchange_mapi_connection_fetch_gal (priv->conn,
- mapi_book_utils_get_prop_list, GET_ALL_KNOWN_IDS,
- fetch_gal_cb, &fgd, &mapi_error);
-
- if (fgd.book_view) {
- GError *error = NULL;
-
- if (mapi_error) {
- mapi_error_to_edb_error (&error, mapi_error, E_DATA_BOOK_STATUS_OTHER_ERROR, _("Failed to fetch GAL entries"));
- g_error_free (mapi_error);
- }
-
- e_data_book_view_notify_complete (fgd.book_view, error);
- e_data_book_view_unref (fgd.book_view);
-
- if (error)
- g_error_free (error);
- }
-
- tmp = g_strdup_printf("%d", priv->kill_cache_build ? 0 : (gint)time (NULL));
- e_book_backend_cache_set_time (priv->cache, tmp);
- printf("setting time %s\n", tmp);
- g_free (tmp);
+ GCancellable *cancelled;
+ GHashTable *uids;
+};
- e_file_cache_thaw_changes (E_FILE_CACHE (priv->cache));
+static gboolean
+fetch_gal_uids_cb (ExchangeMapiConnection *conn, uint32_t row_index, uint32_t n_rows, struct SRow *aRow, gpointer data)
+{
+ const gchar *uid;
+ struct FetchGalUidsData *fgud = data;
- e_book_backend_summary_save (priv->summary);
+ g_return_val_if_fail (conn != NULL, FALSE);
+ g_return_val_if_fail (aRow != NULL, FALSE);
+ g_return_val_if_fail (data != NULL, FALSE);
- priv->is_cache_ready = !priv->kill_cache_build;
- priv->is_summary_ready = !priv->kill_cache_build;
+ uid = exchange_mapi_util_find_row_propval (aRow, PR_EMAIL_ADDRESS_UNICODE);
+ if (uid)
+ g_hash_table_insert (fgud->uids, g_strdup (uid), GINT_TO_POINTER (1));
- return NULL;
+ return !g_cancellable_is_cancelled (fgud->cancelled);
}
static void
-e_book_backend_mapi_gal_get_supported_fields (EBookBackend *backend,
- EDataBook *book,
- guint32 opid)
-
+ebbm_gal_create_contact (EBookBackendMAPI *ebma, const gchar *vcard, EContact **contact, GError **error)
{
- GList *fields;
-
- fields = mapi_book_utils_get_supported_fields ();
- e_data_book_respond_get_supported_fields (book,
- opid,
- NULL /* Success */,
- fields);
- g_list_free (fields);
+ g_propagate_error (error, EDB_ERROR (PERMISSION_DENIED));
}
static void
-e_book_backend_mapi_gal_get_required_fields (EBookBackend *backend,
- EDataBook *book,
- guint32 opid)
+ebbm_gal_remove_contacts (EBookBackendMAPI *ebma, const GList *ids, GList **removed_ids, GError **error)
{
- GList *fields = NULL;
-
- fields = g_list_append (fields, (gchar *) e_contact_field_name (E_CONTACT_FILE_AS));
- e_data_book_respond_get_required_fields (book,
- opid,
- NULL /* Success */,
- fields);
- g_list_free (fields);
+ g_propagate_error (error, EDB_ERROR (PERMISSION_DENIED));
}
static void
-e_book_backend_mapi_gal_authenticate_user (EBookBackend *backend,
- EDataBook *book,
- guint32 opid,
- const gchar *user,
- const gchar *passwd,
- const gchar *auth_method)
+ebbm_gal_modify_contact (EBookBackendMAPI *ebma, const gchar *vcard, EContact **contact, GError **error)
{
- EBookBackendMAPIGAL *ebmapi = (EBookBackendMAPIGAL *) backend;
- EBookBackendMAPIGALPrivate *priv = ebmapi->priv;
- GError *mapi_error = NULL;
-
- if (enable_debug) {
- printf ("mapi: authenticate user\n");
- }
-
- switch (priv->mode) {
- case E_DATA_BOOK_MODE_LOCAL:
- e_book_backend_notify_writable (backend, FALSE);
- e_book_backend_set_is_writable (E_BOOK_BACKEND(backend), FALSE);
- e_book_backend_notify_connection_status (backend, FALSE);
- e_data_book_respond_authenticate_user (book, opid, NULL /* Success */);
- return;
-
- case E_DATA_BOOK_MODE_REMOTE:
- g_static_mutex_lock (&priv->running_mutex);
-
- /* rather reuse already established connection */
- priv->conn = exchange_mapi_connection_find (priv->profile);
- if (priv->conn && !exchange_mapi_connection_connected (priv->conn))
- exchange_mapi_connection_reconnect (priv->conn, passwd, &mapi_error);
- else if (!priv->conn)
- priv->conn = exchange_mapi_connection_new (priv->profile, passwd, &mapi_error);
-
- if (!priv->conn || mapi_error) {
- GError *err = NULL;
-
- if (priv->conn) {
- g_object_unref (priv->conn);
- priv->conn = NULL;
- }
-
- mapi_error_to_edb_error (&err, mapi_error, E_DATA_BOOK_STATUS_OTHER_ERROR, _("Cannot connect"));
- e_data_book_respond_authenticate_user (book, opid, err);
- g_static_mutex_unlock (&priv->running_mutex);
-
- if (mapi_error)
- g_error_free (mapi_error);
- return;
- }
-
- if (priv->cache && priv->is_cache_ready) {
- printf("FIXME: Should check for an update in the cache\n");
-// g_thread_create ((GThreadFunc) update_cache,
- // backend, FALSE, backend);
- } else if (priv->marked_for_offline && !priv->is_cache_ready) {
- if (!priv->build_cache_thread) {
- /* Means we dont have a cache. Lets build that first */
- printf("Preparing to build cache\n");
- priv->kill_cache_build = FALSE;
- priv->build_cache_thread = g_thread_create ((GThreadFunc) build_cache, ebmapi, TRUE, NULL);
- }
- }
- e_book_backend_set_is_writable (backend, FALSE);
- e_data_book_respond_authenticate_user (book, opid, NULL /* Success */);
- g_static_mutex_unlock (&priv->running_mutex);
- return;
-
- default :
- break;
- }
+ g_propagate_error (error, EDB_ERROR (PERMISSION_DENIED));
}
static gchar *
-get_filename_from_uri (const gchar *uri, const gchar *file)
-{
- gchar *mangled_uri, *filename;
- gint i;
-
- /* mangle the URI to not contain invalid characters */
- mangled_uri = g_strdup (uri);
- for (i = 0; i < strlen (mangled_uri); i++) {
- switch (mangled_uri[i]) {
- case ':' :
- case '/' :
- mangled_uri[i] = '_';
- }
- }
-
- /* generate the file name */
- filename = g_build_filename (g_get_home_dir (), ".evolution/cache/addressbook",
- mangled_uri, file, NULL);
-
- /* free memory */
- g_free (mangled_uri);
-
- return filename;
-}
-
-static void
-e_book_backend_mapi_gal_create_contact (EBookBackend *backend,
- EDataBook *book,
- guint32 opid,
- const gchar *vcard)
+ebbm_gal_get_status_message (EBookBackendMAPI *ebma, gint index, gint total)
{
- e_data_book_respond_create (book, opid,
- EDB_ERROR (PERMISSION_DENIED),
- NULL);
-}
-
-static void
-e_book_backend_mapi_gal_remove_contacts (EBookBackend *backend,
- EDataBook *book,
- guint32 opid,
- GList *ids)
-{
- e_data_book_respond_remove_contacts (book, opid,
- EDB_ERROR (PERMISSION_DENIED),
- NULL);
-}
+ if (index <= 0)
+ return NULL;
-static void
-e_book_backend_mapi_gal_modify_contact (EBookBackend *backend,
- EDataBook *book,
- guint32 opid,
- const gchar *vcard)
-{
- e_data_book_respond_modify (book, opid,
- EDB_ERROR (PERMISSION_DENIED),
- NULL);
+ return g_strdup_printf (
+ total <= 0 ?
+ /* Translators : This is used to cache the downloaded contacts from GAL.
+ %d is an index of the GAL entry. */
+ _("Caching GAL contact %d") :
+ /* Translators : This is used to cache the downloaded contacts from GAL.
+ The first %d is an index of the GAL entry,
+ the second %d is total count of entries in GAL. */
+ _("Caching GAL contact %d/%d"),
+ index, total);
}
static void
-e_book_backend_mapi_gal_load_source (EBookBackend *backend,
- ESource *source,
- gboolean only_if_exists,
- GError **perror)
+ebbm_gal_fetch_contacts (EBookBackendMAPI *ebma, struct mapi_SRestriction *restriction, EDataBookView *book_view, gpointer notify_contact_data, GError **error)
{
- EBookBackendMAPIGALPrivate *priv = ((EBookBackendMAPIGAL *) backend)->priv;
- const gchar *offline, *tmp;
-
- if (enable_debug)
- printf("MAPI load source\n");
-
- if (e_book_backend_is_loaded (backend))
- return /* Success */;
-
- offline = e_source_get_property (source, "offline_sync");
- if (offline && g_str_equal (offline, "1"))
- priv->marked_for_offline = TRUE;
+ GError *mapi_error = NULL;
+ struct FetchGalData fgd = { 0 };
+ ExchangeMapiConnection *conn;
- /* Either we are in Online mode or this is marked for offline */
+ e_book_backend_mapi_lock_connection (ebma);
- priv->uri = e_source_get_uri (source);
+ conn = e_book_backend_mapi_get_connection (ebma);
+ if (!conn) {
+ e_book_backend_mapi_unlock_connection (ebma);
+ g_propagate_error (error, EDB_ERROR (REPOSITORY_OFFLINE));
- if (priv->mode == E_DATA_BOOK_MODE_LOCAL &&
- !priv->marked_for_offline ) {
- g_propagate_error (perror, EDB_ERROR (OFFLINE_UNAVAILABLE));
return;
}
- g_free (priv->summary_file_name);
- priv->summary_file_name = get_filename_from_uri (priv->uri, "cache.summary");
- if (priv->summary) g_object_unref (priv->summary);
- priv->summary = e_book_backend_summary_new (priv->summary_file_name, SUMMARY_FLUSH_TIMEOUT);
-
- if (priv->marked_for_offline) {
- if (g_file_test (priv->summary_file_name, G_FILE_TEST_EXISTS)) {
- e_book_backend_summary_load (priv->summary);
- priv->is_summary_ready = TRUE;
- }
-
- /* Load the cache as well.*/
- if (e_book_backend_cache_exists (priv->uri)) {
- gchar *last_time;
-
- priv->cache = e_book_backend_cache_new (priv->uri);
-
- last_time = e_book_backend_cache_get_time (priv->cache);
- priv->is_cache_ready = last_time && !g_str_equal (last_time, "0");
- g_free (last_time);
- }
- //FIXME: We may have to do a time based reload. Or deltas should upload.
- }
-
- e_book_backend_set_is_loaded (E_BOOK_BACKEND (backend), TRUE);
- e_book_backend_set_is_writable (backend, FALSE);
- if (priv->mode == E_DATA_BOOK_MODE_LOCAL) {
- e_book_backend_set_is_writable (backend, FALSE);
- e_book_backend_notify_writable (backend, FALSE);
- e_book_backend_notify_connection_status (backend, FALSE);
- if (!priv->cache) {
- printf("Unfortunately the cache is not yet created\n");
- g_propagate_error (perror, EDB_ERROR (OFFLINE_UNAVAILABLE));
- return;
- }
- } else {
- e_book_backend_notify_connection_status (backend, TRUE);
- }
-
- priv->profile = g_strdup (e_source_get_property (source, "profile"));
- exchange_mapi_util_mapi_id_from_string (e_source_get_property (source, "folder-id"), &priv->fid);
+ fgd.ebma = ebma;
+ fgd.book_view = book_view;
+ fgd.notify_contact_data = notify_contact_data;
+ fgd.fid = exchange_mapi_connection_get_default_folder_id (conn, olFolderContacts, NULL);
- tmp = e_source_get_property (source, "folder-id");
+ exchange_mapi_connection_fetch_gal (conn, restriction,
+ mapi_book_utils_get_prop_list, GET_ALL_KNOWN_IDS,
+ fetch_gal_cb, &fgd, &mapi_error);
- /* Once aunthentication in address book works this can be removed */
- if (priv->mode == E_DATA_BOOK_MODE_LOCAL) {
- return /* Success */;
+ if (mapi_error) {
+ mapi_error_to_edb_error (error, mapi_error, E_DATA_BOOK_STATUS_OTHER_ERROR, _("Failed to fetch GAL entries"));
+ g_error_free (mapi_error);
}
- // writable property will be set in authenticate_user callback
- e_book_backend_set_is_loaded (E_BOOK_BACKEND (backend), TRUE);
- e_book_backend_notify_connection_status (E_BOOK_BACKEND (backend), TRUE);
-
- if (enable_debug)
- printf("For profile %s and folder %s - %016" G_GINT64_MODIFIER "X\n", priv->profile, tmp, priv->fid);
-}
-
-static void
-e_book_backend_mapi_gal_set_mode (EBookBackend *backend, EDataBookMode mode)
-{
- EBookBackendMAPIGALPrivate *priv = ((EBookBackendMAPIGAL *) backend)->priv;
-
- if (enable_debug)
- printf("mapi: set_mode \n");
-
- priv->mode = mode;
- if (e_book_backend_is_loaded (backend)) {
- if (mode == E_DATA_BOOK_MODE_LOCAL) {
- e_book_backend_notify_writable (backend, FALSE);
- e_book_backend_set_is_writable (backend, FALSE);
- e_book_backend_notify_connection_status (backend, FALSE);
- /* FIXME: Uninitialize mapi here. may be.*/
- }
- else if (mode == E_DATA_BOOK_MODE_REMOTE) {
- e_book_backend_notify_writable (backend, FALSE);
- e_book_backend_set_is_writable (backend, FALSE);
- e_book_backend_notify_connection_status (backend, TRUE);
-// e_book_backend_notify_auth_required (backend); //FIXME: WTH is this required.
- }
- }
-}
-
-typedef struct {
- EBookBackendMAPIGAL *bg;
- EDataBookView *book_view;
- gboolean stop;
-} BESearchClosure;
-
-static BESearchClosure*
-init_closure (EDataBookView *book_view, EBookBackendMAPIGAL *bg)
-{
- BESearchClosure *closure;
-
- g_return_val_if_fail (bg != NULL, NULL);
- g_return_val_if_fail (bg->priv != NULL, NULL);
- g_return_val_if_fail (bg->priv->view_to_closure_hash != NULL, NULL);
-
- closure = g_new0 (BESearchClosure, 1);
- closure->bg = bg;
- closure->book_view = book_view;
- closure->stop = FALSE;
-
- g_hash_table_insert (bg->priv->view_to_closure_hash, g_object_ref (book_view), closure);
-
- return closure;
+ e_book_backend_mapi_unlock_connection (ebma);
}
static void
-destroy_closure (BESearchClosure *closure)
+ebbm_gal_fetch_known_uids (EBookBackendMAPI *ebma, GCancellable *cancelled, GHashTable *uids, GError **error)
{
- g_return_if_fail (closure != NULL);
-
- if (closure->book_view)
- g_object_unref (closure->book_view);
- g_free (closure);
-}
-
-static void
-stop_book_view (EDataBookView *book_view, BESearchClosure *closure, EBookBackendMAPIGAL *mapi_backend)
-{
- g_return_if_fail (closure != NULL);
-
- closure->stop = TRUE;
-}
-
-static void
-untrack_book_view (EBookBackendMAPIGAL *mapi_backend, EDataBookView *book_view)
-{
- g_return_if_fail (mapi_backend != NULL);
- g_return_if_fail (mapi_backend->priv != NULL);
- g_return_if_fail (mapi_backend->priv->view_to_closure_hash != NULL);
- g_return_if_fail (book_view != NULL);
-
- g_hash_table_remove (mapi_backend->priv->view_to_closure_hash, book_view);
-}
-
-static void
-get_contacts_from_cache (EBookBackendMAPIGAL *ebmapi,
- const gchar *query,
- GPtrArray *ids,
- EDataBookView *book_view,
- BESearchClosure *closure)
-{
- gint i;
+ ExchangeMapiConnection *conn;
+ GError *mapi_error = NULL;
+ struct FetchGalUidsData fgud = { 0 };
- for (i = 0; i < ids->len; i ++) {
- gchar *uid;
- EContact *contact;
+ g_return_if_fail (ebma != NULL);
+ g_return_if_fail (cancelled != NULL);
+ g_return_if_fail (uids != NULL);
- if (closure->stop)
- break;
+ e_book_backend_mapi_lock_connection (ebma);
- uid = g_ptr_array_index (ids, i);
- contact = e_book_backend_cache_get_contact (ebmapi->priv->cache, uid);
- if (contact) {
- e_data_book_view_notify_update (book_view, contact);
- g_object_unref (contact);
- }
- }
-}
-#if 0
-static gboolean
-build_restriction_emails_contains (struct mapi_SRestriction *res,
- const gchar *query)
-{
- gchar *email=NULL, *tmp, *tmp1;
-
- /* This currently supports "email foo bar soo" */
- tmp = strdup (query);
-
- tmp = strstr (tmp, "email");
- if (tmp ) {
- tmp = strchr (tmp, '\"');
- if (tmp && ++tmp) {
- tmp = strchr (tmp, '\"');
- if (tmp && ++tmp) {
- tmp1 = tmp;
- tmp1 = strchr (tmp1, '\"');
- if (tmp1) {
- *tmp1 = 0;
- email = tmp;
- }
- }
- }
+ conn = e_book_backend_mapi_get_connection (ebma);
+ if (!conn) {
+ e_book_backend_mapi_unlock_connection (ebma);
+ g_propagate_error (error, EDB_ERROR (REPOSITORY_OFFLINE));
+ return;
}
- if (email==NULL || !strchr (email, '@'))
- return FALSE;
+ fgud.cancelled = cancelled;
+ fgud.uids = uids;
- res->rt = RES_PROPERTY;
- res->res.resProperty.relop = RES_PROPERTY;
- res->res.resProperty.ulPropTag = PROP_TAG(PT_UNICODE, 0x801f); /* EMAIL */
- res->res.resProperty.lpProp.ulPropTag = PROP_TAG(PT_UNICODE, 0x801f); /* EMAIL*/
- res->res.resProperty.lpProp.value.lpszA = email;
+ exchange_mapi_connection_fetch_gal (conn, NULL,
+ mapi_book_utils_get_prop_list, GET_UIDS_ONLY,
+ fetch_gal_uids_cb, &fgud, &mapi_error);
- return TRUE;
-}
-#endif
-
-static void
-book_view_thread (gpointer data)
-{
- BESearchClosure *closure = data;
- EDataBookView *book_view = closure->book_view;
- EBookBackendMAPIGAL *backend = closure->bg;
- EBookBackendMAPIGALPrivate *priv = backend->priv;
- const gchar *query = NULL;
- GPtrArray *ids = NULL;
- GList *contacts = NULL, *temp_list = NULL;
-
- if (enable_debug)
- printf("mapi: book view\n");
-
- book_view_notify_status (book_view, _("Searching"));
- query = e_data_book_view_get_card_query (book_view);
-
- if (!find_book_view (backend))
- e_book_backend_add_book_view (E_BOOK_BACKEND (backend), book_view);
-
- switch (priv->mode) {
- case E_DATA_BOOK_MODE_REMOTE:
- if (!priv->conn) {
- GError *err = EDB_ERROR (AUTHENTICATION_REQUIRED);
- e_book_backend_notify_auth_required (E_BOOK_BACKEND (backend));
- e_data_book_view_notify_complete (book_view, err);
- g_error_free (err);
- untrack_book_view (backend, book_view);
- destroy_closure (closure);
- return;
- }
-
- if (priv->marked_for_offline && !priv->is_cache_ready) {
- /* To translators : Here Evolution MAPI downloads the entries from the GAL server */
- book_view_notify_status (book_view, _("Downloading GAL entries from serverâ?¦"));
- untrack_book_view (backend, book_view);
- destroy_closure (closure);
- return;
- }
-
- if (priv->marked_for_offline && priv->cache && priv->is_cache_ready) {
- if (priv->is_summary_ready &&
- e_book_backend_summary_is_summary_query (priv->summary, query)) {
- if (enable_debug)
- printf ("reading the contacts from summary \n");
- ids = e_book_backend_summary_search (priv->summary, query);
- if (ids && ids->len > 0)
- get_contacts_from_cache (backend, query, ids, book_view, closure);
- if (ids)
- g_ptr_array_free (ids, TRUE);
- break;
- }
-
- printf("Summary seems to be not there or not a summary query, lets fetch from cache directly\n");
-
- /* We are already cached. Lets return from there. */
- contacts = e_book_backend_cache_get_contacts (priv->cache,
- query);
- temp_list = contacts;
- for (; contacts != NULL; contacts = g_list_next(contacts)) {
- if (closure->stop) {
- for (;contacts != NULL; contacts = g_list_next (contacts))
- g_object_unref (contacts->data);
- break;
- }
- e_data_book_view_notify_update (book_view,
- E_CONTACT(contacts->data));
- g_object_unref (contacts->data);
- }
- if (temp_list)
- g_list_free (temp_list);
- break;
- }
-
- if (e_book_backend_summary_is_summary_query (priv->summary, query)) {
- ids = e_book_backend_summary_search (priv->summary, query);
- if (ids && ids->len > 0)
- get_contacts_from_cache (backend, query, ids, book_view, closure);
- if (ids)
- g_ptr_array_free (ids, TRUE);
- break;
- }
-
- break;
+ if (mapi_error) {
+ mapi_error_to_edb_error (error, mapi_error, E_DATA_BOOK_STATUS_OTHER_ERROR, _("Failed to fetch GAL entries"));
+ g_error_free (mapi_error);
}
- e_data_book_view_notify_complete (book_view, NULL /* Success */);
- untrack_book_view (backend, book_view);
- destroy_closure (closure);
-}
-
-static void
-e_book_backend_mapi_gal_get_contact (EBookBackend *backend,
- EDataBook *book,
- guint32 opid,
- const gchar *id)
-{
- if (enable_debug)
- printf ("mapi: get contact %s\n", id);
-
- e_data_book_respond_get_contact (book, opid, EDB_ERROR (NOT_SUPPORTED), NULL);
-}
-
-static void
-e_book_backend_mapi_gal_get_contact_list (EBookBackend *backend,
- EDataBook *book,
- guint32 opid,
- const gchar *query )
-{
- /*EBookBackendMAPIGALPrivate *priv = ((EBookBackendMAPIGAL *) backend)->priv;*/
-
- if (enable_debug)
- printf("mapi: get contact list %s\n", query);
-
- e_data_book_respond_get_contact_list (book, opid, EDB_ERROR (NOT_SUPPORTED), NULL);
-}
-
-static void
-e_book_backend_mapi_gal_start_book_view (EBookBackend *backend,
- EDataBookView *book_view)
-{
- BESearchClosure *closure = init_closure (book_view, E_BOOK_BACKEND_MAPIGAL (backend));
-
- g_return_if_fail (closure != NULL);
-
- if (enable_debug)
- printf ("mapi: start_book_view...\n");
-
- g_thread_create ((GThreadFunc) book_view_thread, closure, FALSE, NULL);
-}
-
-static void
-e_book_backend_mapi_gal_stop_book_view (EBookBackend *backend,
- EDataBookView *book_view)
-{
- if (enable_debug)
- printf("mapi: stop book view\n");
-
- untrack_book_view (E_BOOK_BACKEND_MAPIGAL (backend), book_view);
-}
-
-static void
-e_book_backend_mapi_gal_get_changes (EBookBackend *backend, EDataBook *book, guint32 opid, const gchar *change_id)
-{
- if (enable_debug)
- printf ("mapi: get changes\n");
-
- e_data_book_respond_get_changes (book, opid, EDB_ERROR (NOT_SUPPORTED), NULL);
-}
-
-static void
-e_book_backend_mapi_gal_get_supported_auth_methods (EBookBackend *backend, EDataBook *book, guint32 opid)
-{
- GList *auth_methods = NULL;
- gchar *auth_method;
-
- if (enable_debug)
- printf ("mapi get_supported_auth_methods...\n");
-
- auth_method = g_strdup_printf ("plain/password");
- auth_methods = g_list_append (auth_methods, auth_method);
- e_data_book_respond_get_supported_auth_methods (book,
- opid,
- NULL /* Success */,
- auth_methods);
- g_free (auth_method);
- g_list_free (auth_methods);
-}
-
-static void
-e_book_backend_mapi_gal_cancel_operation (EBookBackend *backend, EDataBook *book, GError **perror)
-{
- if (enable_debug)
- printf ("mapi cancel_operation...\n");
- g_propagate_error (perror, EDB_ERROR (COULD_NOT_CANCEL));
-}
-
-static void
-e_book_backend_mapi_gal_remove (EBookBackend *backend, EDataBook *book, guint32 opid)
-{
- e_data_book_respond_remove (book, opid, EDB_ERROR (PERMISSION_DENIED));
+ e_book_backend_mapi_unlock_connection (ebma);
}
static void
e_book_backend_mapi_gal_init (EBookBackendMAPIGAL *backend)
{
- EBookBackendMAPIGALPrivate *priv;
-
- priv = g_new0 (EBookBackendMAPIGALPrivate, 1);
- /* Priv Struct init */
- backend->priv = priv;
-
- priv->build_cache_thread = NULL;
- priv->view_to_closure_hash = g_hash_table_new (g_direct_hash, g_direct_equal);
- g_static_mutex_init (&priv->running_mutex);
-
-/* priv->marked_for_offline = FALSE;
- priv->uri = NULL;
- priv->cache = NULL;
- priv->is_summary_ready = FALSE;
- priv->is_cache_ready = FALSE;
-
-*/ if (g_getenv ("MAPI_DEBUG"))
- enable_debug = TRUE;
- else
- enable_debug = FALSE;
-}
-
-static void
-e_book_backend_mapi_gal_dispose (GObject *object)
-{
- EBookBackendMAPIGAL *mapi_backend = E_BOOK_BACKEND_MAPIGAL (object);
- EBookBackendMAPIGALPrivate *priv = mapi_backend->priv;
-
- if (priv) {
- if (priv->view_to_closure_hash) {
- g_hash_table_foreach (priv->view_to_closure_hash, (GHFunc) stop_book_view, mapi_backend);
- g_hash_table_destroy (priv->view_to_closure_hash);
- priv->view_to_closure_hash = NULL;
- }
-
- if (priv->build_cache_thread) {
- priv->kill_cache_build = TRUE;
- g_thread_join (priv->build_cache_thread);
- priv->build_cache_thread = NULL;
- }
-
- #define FREE(x) if (x) { g_free (x); x = NULL; }
- #define UNREF(x) if (x) { g_object_unref (x); x = NULL; }
-
- /* this will also ensure any pending authentication
- request is finished and it's safe to free memory */
- g_static_mutex_lock (&priv->running_mutex);
-
- UNREF (priv->conn);
- UNREF (priv->cache);
- UNREF (priv->summary);
-
- FREE (priv->profile);
- FREE (priv->uri);
- FREE (priv->summary_file_name);
-
- g_static_mutex_unlock (&priv->running_mutex);
- g_static_mutex_free (&priv->running_mutex);
-
- FREE (mapi_backend->priv);
-
- #undef UNREF
- #undef FREE
- }
-
- /* Chain up to parent's dispose() method. */
- if (G_OBJECT_CLASS (e_book_backend_mapi_gal_parent_class)->dispose)
- G_OBJECT_CLASS (e_book_backend_mapi_gal_parent_class)->dispose (object);
+ backend->priv = G_TYPE_INSTANCE_GET_PRIVATE (backend, E_TYPE_BOOK_BACKEND_MAPI_GAL, EBookBackendMAPIGALPrivate);
}
static void
e_book_backend_mapi_gal_class_init (EBookBackendMAPIGALClass *klass)
{
- GObjectClass *object_class = G_OBJECT_CLASS (klass);
- EBookBackendClass *parent_class;
+ EBookBackendMAPIClass *parent_class;
- parent_class = E_BOOK_BACKEND_CLASS (klass);
+ g_type_class_add_private (klass, sizeof (EBookBackendMAPIGALPrivate));
+
+ parent_class = E_BOOK_BACKEND_MAPI_CLASS (klass);
/* Set the virtual methods. */
- parent_class->create_contact = e_book_backend_mapi_gal_create_contact;
- parent_class->remove_contacts = e_book_backend_mapi_gal_remove_contacts;
- parent_class->modify_contact = e_book_backend_mapi_gal_modify_contact;
- parent_class->load_source = e_book_backend_mapi_gal_load_source;
- parent_class->get_static_capabilities = e_book_backend_mapi_gal_get_static_capabilities;
-
- parent_class->get_contact = e_book_backend_mapi_gal_get_contact;
- parent_class->get_contact_list = e_book_backend_mapi_gal_get_contact_list;
- parent_class->start_book_view = e_book_backend_mapi_gal_start_book_view;
- parent_class->stop_book_view = e_book_backend_mapi_gal_stop_book_view;
- parent_class->get_changes = e_book_backend_mapi_gal_get_changes;
- parent_class->authenticate_user = e_book_backend_mapi_gal_authenticate_user;
- parent_class->get_supported_fields = e_book_backend_mapi_gal_get_supported_fields;
- parent_class->get_required_fields = e_book_backend_mapi_gal_get_required_fields;
- parent_class->get_supported_auth_methods = e_book_backend_mapi_gal_get_supported_auth_methods;
- parent_class->cancel_operation = e_book_backend_mapi_gal_cancel_operation;
- parent_class->set_mode = e_book_backend_mapi_gal_set_mode;
- parent_class->remove = e_book_backend_mapi_gal_remove;
-
- object_class->dispose = e_book_backend_mapi_gal_dispose;
+ parent_class->op_create_contact = ebbm_gal_create_contact;
+ parent_class->op_remove_contacts = ebbm_gal_remove_contacts;
+ parent_class->op_modify_contact = ebbm_gal_modify_contact;
+
+ parent_class->op_get_status_message = ebbm_gal_get_status_message;
+ parent_class->op_fetch_contacts = ebbm_gal_fetch_contacts;
+ parent_class->op_fetch_known_uids = ebbm_gal_fetch_known_uids;
}
/**
@@ -923,10 +234,7 @@ e_book_backend_mapi_gal_new (void)
{
EBookBackendMAPIGAL *backend;
- if (enable_debug)
- printf ("\ne_book_backend_mapi_gal_new...\n");
-
- backend = g_object_new (E_TYPE_BOOK_BACKEND_MAPIGAL, NULL);
+ backend = g_object_new (E_TYPE_BOOK_BACKEND_MAPI_GAL, NULL);
return E_BOOK_BACKEND (backend);
}
diff --git a/src/addressbook/e-book-backend-mapi-gal.h b/src/addressbook/e-book-backend-mapi-gal.h
index c6c00f7..e9f1e82 100644
--- a/src/addressbook/e-book-backend-mapi-gal.h
+++ b/src/addressbook/e-book-backend-mapi-gal.h
@@ -21,34 +21,34 @@
*
*/
-#ifndef __E_BOOK_BACKEND_MAPIGAL_H__
-#define __E_BOOK_BACKEND_MAPIGAL_H__
+#ifndef __E_BOOK_BACKEND_MAPI_GAL_H__
+#define __E_BOOK_BACKEND_MAPI_GAL_H__
-#include <libedata-book/e-book-backend.h>
-#include <libedata-book/e-book-backend-sync.h>
-#include "exchange-mapi-connection.h"
-#include "exchange-mapi-defs.h"
-#include "exchange-mapi-utils.h"
+#include "e-book-backend-mapi.h"
+
+G_BEGIN_DECLS
+
+#define E_TYPE_BOOK_BACKEND_MAPI_GAL (e_book_backend_mapi_gal_get_type ())
+#define E_BOOK_BACKEND_MAPI_GAL(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), E_TYPE_BOOK_BACKEND_MAPI_GAL, EBookBackendMAPIGAL))
+#define E_BOOK_BACKEND_MAPI_GAL_CLASS(k) (G_TYPE_CHECK_CLASS_CAST ((k), E_TYPE_BOOK_BACKEND_MAPI_GAL, EBookBackendMAPIGALClass))
+#define E_IS_BOOK_BACKEND_MAPI_GAL(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), E_TYPE_BOOK_BACKEND_MAPI_GAL))
+#define E_IS_BOOK_BACKEND_MAPI_GAL_CLASS(k) (G_TYPE_CHECK_CLASS_TYPE ((k), E_TYPE_BOOK_BACKEND_MAPI_GAL))
typedef struct _EBookBackendMAPIGALPrivate EBookBackendMAPIGALPrivate;
typedef struct {
- EBookBackend parent_object;
+ EBookBackendMAPI parent_object;
EBookBackendMAPIGALPrivate *priv;
} EBookBackendMAPIGAL;
typedef struct {
- EBookBackendClass parent_class;
+ EBookBackendMAPIClass parent_class;
} EBookBackendMAPIGALClass;
EBookBackend *e_book_backend_mapi_gal_new (void);
-GType e_book_backend_mapi_gal_get_type (void);
+GType e_book_backend_mapi_gal_get_type (void);
-#define E_TYPE_BOOK_BACKEND_MAPIGAL (e_book_backend_mapi_gal_get_type ())
-#define E_BOOK_BACKEND_MAPIGAL(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), E_TYPE_BOOK_BACKEND_MAPIGAL, EBookBackendMAPIGAL))
-#define E_BOOK_BACKEND_MAPIGAL_CLASS(k) (G_TYPE_CHECK_CLASS_CAST ((k), E_TYPE_BOOK_BACKEND_MAPIGAL, EBookBackendMAPIGALClass))
-#define E_IS_BOOK_BACKEND_MAPIGAL(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), E_TYPE_BOOK_BACKEND_MAPIGAL))
-#define E_IS_BOOK_BACKEND_MAPIGAL_CLASS(k) (G_TYPE_CHECK_CLASS_TYPE ((k), E_TYPE_BOOK_BACKEND_MAPIGAL))
+G_END_DECLS
-#endif /* __E_BOOK_BACKEND_MAPIGAL_H__ */
+#endif /* __E_BOOK_BACKEND_MAPI_GAL_H__ */
diff --git a/src/addressbook/e-book-backend-mapi.c b/src/addressbook/e-book-backend-mapi.c
index 582a269..528114f 100644
--- a/src/addressbook/e-book-backend-mapi.c
+++ b/src/addressbook/e-book-backend-mapi.c
@@ -32,198 +32,102 @@
#include <glib/gstdio.h>
#include <glib/gi18n-lib.h>
-#include <sys/time.h>
-/*
-** #include <glib/gi18n-lib.h>
-*/
-
-#include <libedataserver/e-sexp.h>
-#include "libedataserver/e-flag.h"
#include <libebook/e-contact.h>
#include <camel/camel.h>
-#include <libedata-book/e-book-backend-sexp.h>
-#include <libedata-book/e-data-book.h>
-#include <libedata-book/e-data-book-view.h>
-#include <libedata-book/e-book-backend-cache.h>
-#include <libedata-book/e-book-backend-summary.h>
+#include <em-operation-queue.h>
+
+#include "exchange-mapi-utils.h"
+#include "exchange-mapi-defs.h"
+
#include "e-book-backend-mapi.h"
-#include "e-book-backend-mapi-utils.h"
G_DEFINE_TYPE (EBookBackendMAPI, e_book_backend_mapi, E_TYPE_BOOK_BACKEND)
-static gboolean enable_debug = TRUE;
-
struct _EBookBackendMAPIPrivate
{
- gchar *profile;
- ExchangeMapiConnection *conn;
+ EMOperationQueue *op_queue;
- mapi_id_t fid;
- gint mode;
+ GMutex *conn_lock;
+ ExchangeMapiConnection *conn;
+ gchar *profile;
+ gchar *book_uri;
+ EDataBookMode mode;
gboolean marked_for_offline;
- gboolean is_cache_ready;
- gboolean is_summary_ready;
- gboolean is_writable;
- gchar *uri;
- gchar *summary_file_name;
+ GThread *update_cache_thread;
+ GCancellable *update_cache;
+
EBookBackendSummary *summary;
EBookBackendCache *cache;
-
- GStaticMutex running_mutex;
- GHashTable *view_to_closure_hash; /* EDataBookView -> BESearchClosure */
+ GHashTable *running_book_views;
};
-#define SUMMARY_FLUSH_TIMEOUT 5000
-
-#if 0
-static EDataBookView *
-find_book_view (EBookBackendMAPI *ebmapi)
-{
- EList *views = e_book_backend_get_book_views (E_BOOK_BACKEND (ebmapi));
- EIterator *iter;
- EDataBookView *rv = NULL;
-
- if (!views)
- return NULL;
-
- iter = e_list_get_iterator (views);
-
- if (!iter) {
- g_object_unref (views);
- return NULL;
- }
-
- if (e_iterator_is_valid (iter)) {
- /* just always use the first book view */
- EDataBookView *v = (EDataBookView*)e_iterator_get(iter);
- if (v)
- rv = v;
- }
-
- g_object_unref (iter);
- g_object_unref (views);
-
- return rv;
-}
-#endif
-
-static gboolean
-build_restriction_emails_contains (struct mapi_SRestriction *res,
- const gchar *query)
-{
- gchar *email=NULL, *tmp, *tmp1;
-
- /* This currently supports "email foo bar soo" */
- tmp = strdup (query);
-
- tmp = strstr (tmp, "email");
- if (tmp ) {
- tmp = strchr (tmp, '\"');
- if (tmp && ++tmp) {
- tmp = strchr (tmp, '\"');
- if (tmp && ++tmp) {
- tmp1 = tmp;
- tmp1 = strchr (tmp1, '\"');
- if (tmp1) {
- *tmp1 = 0;
- email = tmp;
- }
- }
- }
- }
-
- if (email==NULL || !strchr (email, '@'))
- return FALSE;
+#define SUMMARY_FLUSH_TIMEOUT_SECS 60
- res->rt = RES_PROPERTY;
- res->res.resProperty.relop = RES_PROPERTY;
- res->res.resProperty.ulPropTag = PROP_TAG(PT_UNICODE, 0x801f); /* EMAIL */
- res->res.resProperty.lpProp.ulPropTag = PROP_TAG(PT_UNICODE, 0x801f); /* EMAIL*/
- res->res.resProperty.lpProp.value.lpszA = email;
+#define ELEMENT_TYPE_MASK 0xF /* mask where the real type of the element is stored */
- return TRUE;
-}
+#define ELEMENT_TYPE_SIMPLE 0x01
+#define ELEMENT_TYPE_COMPLEX 0x02
-static gboolean
-build_multiple_restriction_emails_contains (ExchangeMapiConnection *conn, mapi_id_t fid, struct mapi_SRestriction *res,
- struct mapi_SRestriction_or *or_res,
- const gchar *query, gchar **to_free)
-{
- gchar *email=NULL, *tmp, *tmp1;
- //Number of restriction to apply
- guint res_count = 6;
-
- g_return_val_if_fail (to_free != NULL, FALSE);
-
- /* This currently supports "email foo bar soo" */
- *to_free = strdup (query);
-
- tmp = strstr (*to_free, "email");
- if (tmp ) {
- tmp = strchr (tmp, '\"');
- if (tmp && ++tmp) {
- tmp = strchr (tmp, '\"');
- if (tmp && ++tmp) {
- tmp1 = tmp;
- tmp1 = strchr (tmp1, '\"');
- if (tmp1) {
- *tmp1 = 0;
- email = tmp;
- }
- }
- }
- }
+#define ELEMENT_TYPE_NAMEDID 0x10
- if (email==NULL || !strchr (email, '@')) {
- g_free (*to_free);
- *to_free = NULL;
+static const struct field_element_mapping {
+ EContactField field_id;
+ gint element_type;
+ gint mapi_id;
+ gint contact_type;
+ } mappings [] = {
- return FALSE;
- }
+ { E_CONTACT_UID, PT_UNICODE, PR_EMAIL_ADDRESS_UNICODE, ELEMENT_TYPE_SIMPLE},
+ { E_CONTACT_REV, PT_SYSTIME, PR_LAST_MODIFICATION_TIME, ELEMENT_TYPE_SIMPLE},
- or_res[0].rt = RES_CONTENT;
- or_res[0].res.resContent.fuzzy = FL_FULLSTRING | FL_IGNORECASE;
- or_res[0].res.resContent.ulPropTag = PR_EMS_AB_MANAGER_T_UNICODE;
- or_res[0].res.resContent.lpProp.value.lpszA = email;
+ { E_CONTACT_FILE_AS, PT_UNICODE, PidLidFileUnder, ELEMENT_TYPE_SIMPLE | ELEMENT_TYPE_NAMEDID},
+ { E_CONTACT_FULL_NAME, PT_UNICODE, PR_DISPLAY_NAME_UNICODE, ELEMENT_TYPE_SIMPLE },
+ { E_CONTACT_GIVEN_NAME, PT_UNICODE, PR_GIVEN_NAME_UNICODE, ELEMENT_TYPE_SIMPLE},
+ { E_CONTACT_FAMILY_NAME, PT_UNICODE, PR_SURNAME_UNICODE, ELEMENT_TYPE_SIMPLE},
+ { E_CONTACT_NICKNAME, PT_UNICODE, PR_NICKNAME_UNICODE, ELEMENT_TYPE_SIMPLE },
- or_res[1].rt = RES_CONTENT;
- or_res[1].res.resContent.fuzzy = FL_FULLSTRING | FL_IGNORECASE;
- or_res[1].res.resContent.ulPropTag = PR_DISPLAY_NAME_UNICODE;
- or_res[1].res.resContent.lpProp.value.lpszA = email;
+ { E_CONTACT_EMAIL_1, PT_UNICODE, PidLidEmail1OriginalDisplayName, ELEMENT_TYPE_SIMPLE | ELEMENT_TYPE_NAMEDID},
+ { E_CONTACT_EMAIL_2, PT_UNICODE, PidLidEmail2EmailAddress, ELEMENT_TYPE_SIMPLE | ELEMENT_TYPE_NAMEDID},
+ { E_CONTACT_EMAIL_3, PT_UNICODE, PidLidEmail3EmailAddress, ELEMENT_TYPE_SIMPLE | ELEMENT_TYPE_NAMEDID},
+ { E_CONTACT_IM_AIM, PT_UNICODE, PidLidInstantMessagingAddress, ELEMENT_TYPE_COMPLEX | ELEMENT_TYPE_NAMEDID},
- or_res[2].rt = RES_CONTENT;
- or_res[2].res.resContent.fuzzy = FL_FULLSTRING | FL_IGNORECASE;
- or_res[2].res.resContent.ulPropTag = PR_GIVEN_NAME_UNICODE;
- or_res[2].res.resContent.lpProp.value.lpszA = email;
+ { E_CONTACT_PHONE_BUSINESS, PT_UNICODE, PR_OFFICE_TELEPHONE_NUMBER_UNICODE, ELEMENT_TYPE_SIMPLE},
+ { E_CONTACT_PHONE_HOME, PT_UNICODE, PR_HOME_TELEPHONE_NUMBER_UNICODE, ELEMENT_TYPE_SIMPLE},
+ { E_CONTACT_PHONE_MOBILE, PT_UNICODE, PR_MOBILE_TELEPHONE_NUMBER_UNICODE, ELEMENT_TYPE_SIMPLE},
+ { E_CONTACT_PHONE_HOME_FAX, PT_UNICODE, PR_HOME_FAX_NUMBER_UNICODE, ELEMENT_TYPE_SIMPLE},
+ { E_CONTACT_PHONE_BUSINESS_FAX, PT_UNICODE, PR_BUSINESS_FAX_NUMBER_UNICODE, ELEMENT_TYPE_SIMPLE},
+ { E_CONTACT_PHONE_PAGER, PT_UNICODE, PR_PAGER_TELEPHONE_NUMBER_UNICODE, ELEMENT_TYPE_SIMPLE},
+ { E_CONTACT_PHONE_ASSISTANT, PT_UNICODE, PR_ASSISTANT_TELEPHONE_NUMBER_UNICODE, ELEMENT_TYPE_SIMPLE},
+ { E_CONTACT_PHONE_COMPANY, PT_UNICODE, PR_COMPANY_MAIN_PHONE_NUMBER_UNICODE, ELEMENT_TYPE_SIMPLE},
- or_res[3].rt = RES_CONTENT;
- or_res[3].res.resContent.fuzzy = FL_FULLSTRING | FL_IGNORECASE;
- or_res[3].res.resContent.ulPropTag = exchange_mapi_connection_resolve_named_prop (conn, fid, PidLidEmail1OriginalDisplayName, NULL);
- or_res[3].res.resContent.lpProp.value.lpszA = email;
+ { E_CONTACT_HOMEPAGE_URL, PT_UNICODE, PidLidHtml, ELEMENT_TYPE_SIMPLE | ELEMENT_TYPE_NAMEDID},
+ { E_CONTACT_FREEBUSY_URL, PT_UNICODE, PidLidFreeBusyLocation, ELEMENT_TYPE_SIMPLE | ELEMENT_TYPE_NAMEDID},
- or_res[4].rt = RES_CONTENT;
- or_res[4].res.resContent.fuzzy = FL_FULLSTRING | FL_IGNORECASE;
- or_res[4].res.resContent.ulPropTag = exchange_mapi_connection_resolve_named_prop (conn, fid, PidLidEmail2OriginalDisplayName, NULL);
- or_res[4].res.resContent.lpProp.value.lpszA = email;
+ { E_CONTACT_ROLE, PT_UNICODE, PR_PROFESSION_UNICODE, ELEMENT_TYPE_SIMPLE},
+ { E_CONTACT_TITLE, PT_UNICODE, PR_TITLE_UNICODE, ELEMENT_TYPE_SIMPLE},
+ { E_CONTACT_ORG, PT_UNICODE, PR_COMPANY_NAME_UNICODE, ELEMENT_TYPE_SIMPLE},
+ { E_CONTACT_ORG_UNIT, PT_UNICODE, PR_DEPARTMENT_NAME_UNICODE, ELEMENT_TYPE_SIMPLE},
+ { E_CONTACT_MANAGER, PT_UNICODE, PR_MANAGER_NAME_UNICODE, ELEMENT_TYPE_SIMPLE},
+ { E_CONTACT_ASSISTANT, PT_UNICODE, PR_ASSISTANT_UNICODE, ELEMENT_TYPE_SIMPLE},
- or_res[5].rt = RES_CONTENT;
- or_res[5].res.resContent.fuzzy = FL_FULLSTRING | FL_IGNORECASE;
- or_res[5].res.resContent.ulPropTag = exchange_mapi_connection_resolve_named_prop (conn, fid, PidLidEmail3OriginalDisplayName, NULL);
- or_res[5].res.resContent.lpProp.value.lpszA = email;
+ { E_CONTACT_OFFICE, PT_UNICODE, PR_OFFICE_LOCATION_UNICODE, ELEMENT_TYPE_SIMPLE},
+ { E_CONTACT_SPOUSE, PT_UNICODE, PR_SPOUSE_NAME_UNICODE, ELEMENT_TYPE_SIMPLE},
- res = g_new0 (struct mapi_SRestriction, 1);
+ { E_CONTACT_BIRTH_DATE, PT_SYSTIME, PR_BIRTHDAY, ELEMENT_TYPE_COMPLEX},
+ { E_CONTACT_ANNIVERSARY, PT_SYSTIME, PR_WEDDING_ANNIVERSARY, ELEMENT_TYPE_COMPLEX},
- res->rt = RES_OR;
- res->res.resOr.cRes = res_count;
- res->res.resOr.res = or_res;
+ { E_CONTACT_NOTE, PT_UNICODE, PR_BODY_UNICODE, ELEMENT_TYPE_SIMPLE},
- return TRUE;
-}
+ { E_CONTACT_ADDRESS_HOME, PT_UNICODE, PidLidHomeAddress, ELEMENT_TYPE_COMPLEX | ELEMENT_TYPE_NAMEDID},
+ { E_CONTACT_ADDRESS_WORK, PT_UNICODE, PidLidOtherAddress, ELEMENT_TYPE_COMPLEX | ELEMENT_TYPE_NAMEDID}
+ /* { E_CONTACT_BOOK_URI, ELEMENT_TYPE_SIMPLE, "book_uri"}, */
+ /* { E_CONTACT_CATEGORIES, } */
+ };
static gchar *
-get_filename_from_uri (const gchar *uri, const gchar *file)
+ebbm_get_filename_from_uri (const gchar *uri, const gchar *file)
{
gchar *mangled_uri, *filename;
gint i;
@@ -239,7 +143,7 @@ get_filename_from_uri (const gchar *uri, const gchar *file)
}
/* generate the file name */
- filename = g_build_filename (g_get_home_dir (), ".evolution/cache/addressbook",
+ filename = g_build_filename (g_get_home_dir (), ".evolution", "cache", "addressbook",
mangled_uri, file, NULL);
/* free memory */
@@ -248,1692 +152,1810 @@ get_filename_from_uri (const gchar *uri, const gchar *file)
return filename;
}
-static void
-e_book_backend_mapi_load_source (EBookBackend *backend,
- ESource *source,
- gboolean only_if_exists,
- GError **perror)
+static gboolean
+ebbm_get_cache_time (EBookBackendMAPI *ebma, glong *cache_seconds)
{
- EBookBackendMAPIPrivate *priv = ((EBookBackendMAPI *) backend)->priv;
- const gchar *offline, *tmp;
+ GTimeVal tv = { 0 };
+ gchar *last_update;
- if (enable_debug)
- printf("MAPI load source\n");
+ g_return_val_if_fail (ebma != NULL, FALSE);
+ g_return_val_if_fail (ebma->priv != NULL, FALSE);
+ g_return_val_if_fail (ebma->priv->cache != NULL, FALSE);
+ g_return_val_if_fail (cache_seconds != NULL, FALSE);
- if (e_book_backend_is_loaded (backend))
- return /* Success */;
+ last_update = e_book_backend_cache_get_time (ebma->priv->cache);
+ if (!last_update || !g_time_val_from_iso8601 (last_update, &tv)) {
+ g_free (last_update);
+ return FALSE;
+ }
- offline = e_source_get_property (source, "offline_sync");
- if (offline && g_str_equal (offline, "1"))
- priv->marked_for_offline = TRUE;
+ g_free (last_update);
- /* Either we are in Online mode or this is marked for offline */
+ *cache_seconds = tv.tv_sec;
- priv->uri = e_source_get_uri (source);
+ return TRUE;
+}
- if (priv->mode == E_DATA_BOOK_MODE_LOCAL &&
- !priv->marked_for_offline ) {
- g_propagate_error (perror, EDB_ERROR (OFFLINE_UNAVAILABLE));
- return;
- }
+static void
+ebbm_set_cache_time (EBookBackendMAPI *ebma, glong cache_seconds)
+{
+ g_return_if_fail (ebma != NULL);
+ g_return_if_fail (ebma->priv != NULL);
+ g_return_if_fail (ebma->priv->cache != NULL);
- g_free (priv->summary_file_name);
- priv->summary_file_name = get_filename_from_uri (priv->uri, "cache.summary");
- if (priv->summary) g_object_unref (priv->summary);
- priv->summary = e_book_backend_summary_new (priv->summary_file_name, SUMMARY_FLUSH_TIMEOUT);
+ if (cache_seconds > 0) {
+ gchar *iso_time;
+ GTimeVal tv = { 0 };
- if (priv->marked_for_offline) {
- if (g_file_test (priv->summary_file_name, G_FILE_TEST_EXISTS)) {
- e_book_backend_summary_load (priv->summary);
- priv->is_summary_ready = TRUE;
- }
+ tv.tv_sec = cache_seconds;
+ iso_time = g_time_val_to_iso8601 (&tv);
- /* Load the cache as well.*/
- if (e_book_backend_cache_exists (priv->uri)) {
- priv->cache = e_book_backend_cache_new (priv->uri);
- priv->is_cache_ready = TRUE;
- }
- //FIXME: We may have to do a time based reload. Or deltas should upload.
- } else {
- priv->cache = e_book_backend_cache_new (priv->uri);
- }
+ e_book_backend_cache_set_time (ebma->priv->cache, iso_time ? iso_time : "0");
- e_book_backend_set_is_loaded (E_BOOK_BACKEND (backend), TRUE);
- e_book_backend_set_is_writable (backend, TRUE);
- if (priv->mode == E_DATA_BOOK_MODE_LOCAL) {
- e_book_backend_set_is_writable (backend, FALSE);
- e_book_backend_notify_writable (backend, FALSE);
- e_book_backend_notify_connection_status (backend, FALSE);
- if (!priv->cache) {
- printf("Unfortunately the cache is not yet created\n");
- g_propagate_error (perror, EDB_ERROR (OFFLINE_UNAVAILABLE));
- return;
- }
+ g_free (iso_time);
} else {
- e_book_backend_notify_connection_status (backend, TRUE);
+ e_book_backend_cache_set_time (ebma->priv->cache, "0");
}
+}
- priv->profile = g_strdup (e_source_get_property (source, "profile"));
- exchange_mapi_util_mapi_id_from_string (e_source_get_property (source, "folder-id"), &priv->fid);
+static EDataBookView *
+ebbm_pick_book_view (EBookBackendMAPI *ebma)
+{
+ EList *views = e_book_backend_get_book_views (E_BOOK_BACKEND (ebma));
+ EIterator *iter;
+ EDataBookView *rv = NULL;
+ gint test;
+
+ if (!views)
+ return NULL;
- tmp = e_source_get_property (source, "folder-id");
- printf("Folder is %s %016" G_GINT64_MODIFIER "X\n", tmp, priv->fid);
+ test = e_list_length (views);
- /* Once aunthentication in address book works this can be removed */
- if (priv->mode == E_DATA_BOOK_MODE_LOCAL) {
- return /* Success */;
+ iter = e_list_get_iterator (views);
+
+ if (!iter) {
+ g_object_unref (views);
+ return NULL;
}
- // writable property will be set in authenticate_user callback
- e_book_backend_set_is_loaded (E_BOOK_BACKEND (backend), TRUE);
- e_book_backend_notify_connection_status (E_BOOK_BACKEND (backend), TRUE);
+ if (e_iterator_is_valid (iter)) {
+ /* just always use the first book view */
+ EDataBookView *v = (EDataBookView *) e_iterator_get (iter);
+ if (v)
+ rv = v;
+ }
+
+ g_object_unref (iter);
+ g_object_unref (views);
- if (enable_debug)
- printf("For profile %s and folder %s - %016" G_GINT64_MODIFIER "X\n", priv->profile, tmp, priv->fid);
+ return rv;
}
-static gchar *
-e_book_backend_mapi_get_static_capabilities (EBookBackend *backend)
+struct FetchContactsData
{
- if (enable_debug)
- printf("mapi get_static_capabilities\n");
- //FIXME: Implement this.
-
- return g_strdup ("net,bulk-removes,do-initial-query,contact-lists");
-}
+ glong last_notification;
+ glong last_modification;
+};
-static uint32_t
-string_to_bin (TALLOC_CTX *mem_ctx, const gchar *str, uint8_t **lpb)
+static void
+ebbm_notify_connection_status (EBookBackendMAPI *ebma, gboolean is_online)
{
- uint32_t len, i;
+ EBookBackendMAPIClass *ebmac;
+
+ g_return_if_fail (ebma != NULL);
+ g_return_if_fail (E_IS_BOOK_BACKEND_MAPI (ebma));
- g_return_val_if_fail (str != NULL, 0);
- g_return_val_if_fail (lpb != NULL, 0);
+ e_book_backend_notify_connection_status (E_BOOK_BACKEND (ebma), is_online);
- len = strlen (str);
- g_return_val_if_fail ((len & 1) == 0, 0);
+ ebmac = E_BOOK_BACKEND_MAPI_GET_CLASS (ebma);
+ g_return_if_fail (ebmac != NULL);
- len = len / 2;
- *lpb = talloc_zero_array (mem_ctx, uint8_t, len);
+ if (ebmac->op_connection_status_changed)
+ ebmac->op_connection_status_changed (ebma, is_online);
+}
- i = 0;
- while (*str && i < len) {
- gchar c1 = str[0], c2 = str[1];
- str += 2;
+static void
+ebbm_fetch_contacts (EBookBackendMAPI *ebma, struct mapi_SRestriction *restriction, EDataBookView *book_view, glong *last_modification_secs, GError **error)
+{
+ EBookBackendMAPIClass *ebmac;
+ struct FetchContactsData notify_data = { 0 };
- g_return_val_if_fail ((c1 >= '0' && c1 <= '9') || (c1 >= 'a' && c1 <= 'f') || (c1 >= 'A' && c1 <= 'F'), 0);
- g_return_val_if_fail ((c2 >= '0' && c2 <= '9') || (c2 >= 'a' && c2 <= 'f') || (c2 >= 'A' && c2 <= 'F'), 0);
+ g_return_if_fail (ebma != NULL);
+ g_return_if_fail (ebma->priv != NULL);
+ g_return_if_fail (ebma->priv->conn != NULL);
- #define deHex(x) (((x) >= '0' && (x) <= '9') ? ((x) - '0') : (((x) >= 'a' && (x) <= 'f') ? (x) - 'a' + 10 : (x) - 'A' + 10))
- (*lpb)[i] = (deHex (c1) << 4) | (deHex (c2));
- #undef deHex
- i++;
- }
+ ebmac = E_BOOK_BACKEND_MAPI_GET_CLASS (ebma);
+ g_return_if_fail (ebmac != NULL);
+ g_return_if_fail (ebmac->op_fetch_contacts != NULL);
- return len;
+ ebmac->op_fetch_contacts (ebma, restriction, book_view, ¬ify_data, error);
+
+ if (last_modification_secs && *last_modification_secs < notify_data.last_modification)
+ *last_modification_secs = notify_data.last_modification;
}
-static gint
-cmp_member_id (gconstpointer a, gconstpointer b, gpointer ht)
+static struct mapi_SRestriction *
+ebbm_build_cache_update_restriction (EBookBackendMAPI *ebma, TALLOC_CTX *mem_ctx)
{
- gchar *va, *vb;
- gint res;
+ struct mapi_SRestriction *restriction;
+ EBookBackendMAPIPrivate *priv;
+ struct SPropValue sprop;
+ struct timeval t = { 0 };
+ glong last_update_secs = 0;
- if (!a)
- return b ? -1 : 0;
- if (!b)
- return 1;
+ g_return_val_if_fail (ebma != NULL, NULL);
+ g_return_val_if_fail (mem_ctx != NULL, NULL);
+ g_return_val_if_fail (E_IS_BOOK_BACKEND_MAPI (ebma), NULL);
- va = e_vcard_attribute_get_value ((EVCardAttribute *) a);
- vb = e_vcard_attribute_get_value ((EVCardAttribute *) b);
+ priv = ebma->priv;
+ g_return_val_if_fail (priv != NULL, NULL);
+ g_return_val_if_fail (priv->cache != NULL, NULL);
- res = GPOINTER_TO_INT (g_hash_table_lookup (ht, va)) - GPOINTER_TO_INT (g_hash_table_lookup (ht, vb));
+ if (!ebbm_get_cache_time (ebma, &last_update_secs) || last_update_secs <= 0)
+ return NULL;
- g_free (va);
- g_free (vb);
+ restriction = talloc_zero (mem_ctx, struct mapi_SRestriction);
+ g_assert (restriction != NULL);
- return res;
-}
+ restriction->rt = RES_PROPERTY;
+ restriction->res.resProperty.relop = RELOP_GE;
+ restriction->res.resProperty.ulPropTag = PR_LAST_MODIFICATION_TIME;
-typedef struct {
- EContact *contact;
- EBookBackendCache *cache;
-} MapiCreateitemData;
+ t.tv_sec = last_update_secs;
+ t.tv_usec = 0;
-static gboolean
-mapi_book_write_props (ExchangeMapiConnection *conn, mapi_id_t fid, TALLOC_CTX *mem_ctx, struct SPropValue **values, uint32_t *n_values, gpointer data)
+ set_SPropValue_proptag_date_timeval (&sprop, PR_LAST_MODIFICATION_TIME, &t);
+
+ cast_mapi_SPropValue (
+ #ifdef HAVE_MEMCTX_ON_CAST_MAPI_SPROPVALUE
+ mem_ctx,
+ #endif
+ &(restriction->res.resProperty.lpProp), &sprop);
+
+ return restriction;
+}
+
+static gpointer
+ebbm_update_cache_cb (gpointer data)
{
- /* Do not make this array static, below function modifies it.
- The array is used to just ensure named ids are known later. */
- ResolveNamedIDsData nids[] = {
- { PidLidDistributionListName, 0 },
- { PidLidDistributionListOneOffMembers, 0 },
- { PidLidDistributionListMembers, 0 },
- { PidLidDistributionListChecksum, 0 },
- { PidLidFileUnder, 0 },
- { PidLidFileUnderId, 0 },
- { PidLidEmail1OriginalDisplayName, 0 },
- { PidLidEmail1EmailAddress, 0 },
- { PidLidEmail2EmailAddress, 0 },
- { PidLidEmail3EmailAddress, 0 },
- { PidLidHtml, 0 },
- { PidLidInstantMessagingAddress, 0 },
- { PidLidHomeAddress, 0 },
- { PidLidWorkAddress, 0 },
- { PidLidEmail2OriginalDisplayName, 0 },
- { PidLidEmail3OriginalDisplayName, 0 }
- };
+ EBookBackendMAPI *ebma = (EBookBackendMAPI *) data;
+ EBookBackendMAPIPrivate *priv;
+ EBookBackendMAPIClass *ebmac;
+ glong last_modification_secs = 0;
+ EDataBookView *book_view;
- MapiCreateitemData *mcd = data;
+ g_return_val_if_fail (ebma != NULL, NULL);
+ g_return_val_if_fail (E_IS_BOOK_BACKEND_MAPI (ebma), NULL);
- #define set_str_value(hex, val) G_STMT_START { \
- if (!exchange_mapi_utils_add_spropvalue (mem_ctx, values, n_values, hex, val ? val : "")) \
- return FALSE; \
- } G_STMT_END
+ priv = ebma->priv;
+ g_return_val_if_fail (priv != NULL, NULL);
+ g_return_val_if_fail (priv->cache != NULL, NULL);
+ g_return_val_if_fail (priv->conn != NULL, NULL);
- #define set_str_named_value(named_id, val) G_STMT_START { \
- if (!exchange_mapi_utils_add_spropvalue_named_id (conn, fid, mem_ctx, values, n_values, named_id, val ? val : "")) \
- return FALSE; \
- } G_STMT_END
+ ebmac = E_BOOK_BACKEND_MAPI_GET_CLASS (ebma);
+ g_return_val_if_fail (ebmac != NULL, NULL);
- #define set_str_con_value(hex, field_id) G_STMT_START { \
- if (e_contact_get (mcd->contact, field_id)) { \
- set_str_value (hex, e_contact_get (mcd->contact, field_id)); \
- } } G_STMT_END
+ g_cancellable_reset (priv->update_cache);
- #define set_str_named_con_value(named_id, field_id) G_STMT_START { \
- if (e_contact_get (mcd->contact, field_id)) { \
- set_str_named_value (named_id, e_contact_get (mcd->contact, field_id)); \
- } } G_STMT_END
+ if (!g_cancellable_is_cancelled (priv->update_cache) && ebmac->op_fetch_contacts) {
+ TALLOC_CTX *mem_ctx;
+ struct mapi_SRestriction *restriction;
- g_return_val_if_fail (mcd != NULL, FALSE);
- g_return_val_if_fail (mcd->contact != NULL, FALSE);
- g_return_val_if_fail (conn != NULL, FALSE);
- g_return_val_if_fail (mem_ctx != NULL, FALSE);
- g_return_val_if_fail (values != NULL, FALSE);
- g_return_val_if_fail (n_values != NULL, FALSE);
+ mem_ctx = talloc_init (G_STRFUNC);
+ restriction = ebbm_build_cache_update_restriction (ebma, mem_ctx);
- if (!exchange_mapi_connection_resolve_named_props (conn, fid, nids, G_N_ELEMENTS (nids), NULL))
- return FALSE;
+ /* get time stored in a cache, to always use the latest last modification time */
+ if (!ebbm_get_cache_time (ebma, &last_modification_secs))
+ last_modification_secs = 0;
- if (GPOINTER_TO_INT (e_contact_get (mcd->contact, E_CONTACT_IS_LIST))) {
- EContact *old_contact;
- GList *local, *l;
- struct BinaryArray_r *members, *oneoff_members;
- uint32_t list_size = 0, u32, crc32 = 0;
- GHashTable *member_values = NULL, *member_ids = NULL;
+ ebbm_fetch_contacts (ebma, restriction, NULL, &last_modification_secs, NULL);
- old_contact = e_contact_get (mcd->contact, E_CONTACT_UID) ? e_book_backend_cache_get_contact (mcd->cache, e_contact_get (mcd->contact, E_CONTACT_UID)) : NULL;
- if (old_contact) {
- member_values = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, g_free);
- member_ids = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, NULL);
+ talloc_free (mem_ctx);
+ }
+
+ if (!g_cancellable_is_cancelled (priv->update_cache) && ebmac->op_fetch_known_uids) {
+ GHashTable *uids = g_hash_table_new_full (g_str_hash, g_str_equal, (GDestroyNotify) g_free, NULL);
+ GError *error = NULL;
+
+ ebmac->op_fetch_known_uids (ebma, priv->update_cache, uids, &error);
- local = e_contact_get_attributes (old_contact, E_CONTACT_EMAIL);
- for (l = local; l; l = l->next) {
- EVCardAttribute *attr = l->data;
- GList *param;
+ if (!error && !g_cancellable_is_cancelled (priv->update_cache)) {
+ GSList *cache_keys, *c;
- if (!attr)
+ e_file_cache_freeze_changes (E_FILE_CACHE (priv->cache));
+ cache_keys = e_file_cache_get_keys (E_FILE_CACHE (priv->cache));
+
+ for (c = cache_keys; c; c = c->next) {
+ const gchar *uid = c->data;
+ gchar *uid_str;
+
+ if (!uid || g_hash_table_lookup (uids, uid)
+ || g_str_equal (uid, "populated")
+ || g_str_equal (uid, "last_update_time"))
continue;
- param = e_vcard_attribute_get_param (attr, EMA_X_MEMBERVALUE);
- if (param && param->data && !param->next) {
- g_hash_table_insert (member_values, e_vcard_attribute_get_value (attr), g_strdup (param->data));
- }
+ /* uid is hold by a cache, thus make a copy before remove */
+ uid_str = g_strdup (uid);
- param = e_vcard_attribute_get_param (attr, EMA_X_MEMBERID);
- if (param && param->data && !param->next) {
- g_hash_table_insert (member_ids, e_vcard_attribute_get_value (attr), GINT_TO_POINTER (atoi (param->data)));
- }
+ e_book_backend_mapi_notify_contact_removed (ebma, uid_str);
+
+ g_free (uid_str);
}
- g_object_unref (old_contact);
- g_list_foreach (local, (GFunc)e_vcard_attribute_free, NULL);
- g_list_free (local);
+ ebbm_set_cache_time (ebma, last_modification_secs);
+ e_file_cache_thaw_changes (E_FILE_CACHE (priv->cache));
+ e_book_backend_summary_save (priv->summary);
+
+ g_slist_free (cache_keys);
}
- set_str_value (PR_MESSAGE_CLASS, IPM_DISTLIST);
- u32 = 0xFFFFFFFF;
- if (!exchange_mapi_utils_add_spropvalue_named_id (conn, fid, mem_ctx, values, n_values, PidLidFileUnderId, &u32))
- return FALSE;
- set_str_named_con_value (PidLidFileUnder, E_CONTACT_FILE_AS);
- set_str_named_con_value (PidLidDistributionListName, E_CONTACT_FILE_AS);
- set_str_con_value (PR_DISPLAY_NAME_UNICODE, E_CONTACT_FILE_AS);
- set_str_con_value (PR_NORMALIZED_SUBJECT_UNICODE, E_CONTACT_FILE_AS);
-
-
- local = e_contact_get_attributes (mcd->contact, E_CONTACT_EMAIL);
- if (member_ids)
- local = g_list_sort_with_data (local, cmp_member_id, member_ids);
-
- members = talloc_zero (mem_ctx, struct BinaryArray_r);
- members->cValues = 0;
- members->lpbin = talloc_zero_array (mem_ctx, struct Binary_r, g_list_length (local));
-
- oneoff_members = talloc_zero (mem_ctx, struct BinaryArray_r);
- oneoff_members->cValues = 0;
- oneoff_members->lpbin = talloc_zero_array (mem_ctx, struct Binary_r, g_list_length (local));
-
- for (l = local; l; l = l->next) {
- EVCardAttribute *attr = (EVCardAttribute *) l->data;
- gchar *raw;
- CamelInternetAddress *addr;
-
- if (!attr)
- continue;
-
- raw = e_vcard_attribute_get_value (attr);
- if (!raw)
- continue;
-
- addr = camel_internet_address_new ();
- if (camel_address_decode (CAMEL_ADDRESS (addr), raw) > 0) {
- const gchar *nm = NULL, *eml = NULL;
-
- camel_internet_address_get (addr, 0, &nm, &eml);
- if (eml) {
- /* keep both lists in sync */
- if (member_values && g_hash_table_lookup (member_values, raw)) {
- /* stored ListMembers values when contact's value didn't change */
- members->lpbin[members->cValues].cb = string_to_bin (mem_ctx, g_hash_table_lookup (member_values, raw), &members->lpbin[members->cValues].lpb);
- members->cValues++;
- } else {
- exchange_mapi_util_entryid_generate_oneoff (mem_ctx, &members->lpbin[members->cValues], nm ? nm : "", eml);
- members->cValues++;
- }
-
- exchange_mapi_util_entryid_generate_oneoff (mem_ctx, &oneoff_members->lpbin[oneoff_members->cValues], nm ? nm : "", eml);
- oneoff_members->cValues++;
-
- list_size += MAX (oneoff_members->lpbin[oneoff_members->cValues - 1].cb, members->lpbin[members->cValues - 1].cb);
- crc32 = exchange_mapi_utils_push_crc32 (crc32, members->lpbin[members->cValues - 1].lpb, members->lpbin[members->cValues - 1].cb);
- }
- }
+ g_hash_table_destroy (uids);
+ if (error)
+ g_error_free (error);
+ }
- g_object_unref (addr);
- g_free (raw);
- }
+ book_view = ebbm_pick_book_view (ebma);
+ if (book_view)
+ e_data_book_view_notify_complete (book_view, NULL);
- if (member_values)
- g_hash_table_destroy (member_values);
- if (member_ids)
- g_hash_table_destroy (member_ids);
- g_list_foreach (local, (GFunc)e_vcard_attribute_free, NULL);
- g_list_free (local);
+ return NULL;
+}
- if (!exchange_mapi_utils_add_spropvalue_named_id (conn, fid, mem_ctx, values, n_values,
- PidLidDistributionListOneOffMembers, oneoff_members))
- return FALSE;
+static void
+ebbm_load_source (EBookBackendMAPI *ebma, ESource *source, gboolean only_if_exists, GError **perror)
+{
+ EBookBackendMAPIPrivate *priv = ebma->priv;
+ const gchar *offline;
+ gchar *summary_file_name;
- if (!exchange_mapi_utils_add_spropvalue_named_id (conn, fid, mem_ctx, values, n_values,
- PidLidDistributionListMembers, members))
- return FALSE;
+ if (e_book_backend_is_loaded (E_BOOK_BACKEND (ebma)))
+ return /* Success */;
- if (!exchange_mapi_utils_add_spropvalue_named_id (conn, fid, mem_ctx, values, n_values,
- PidLidDistributionListChecksum, &crc32))
- return FALSE;
+ offline = e_source_get_property (source, "offline_sync");
+ priv->marked_for_offline = offline && g_str_equal (offline, "1");
- /* list_size shouldn't exceed 15000 bytes, is so, use a stream instead of those properties above, but for now... */
- if (list_size > 15000)
- return FALSE;
+ if (priv->book_uri)
+ g_free (priv->book_uri);
+ priv->book_uri = e_source_get_uri (source);
- return TRUE;
- }
+ g_free (priv->profile);
+ priv->profile = g_strdup (e_source_get_property (source, "profile"));
- set_str_value (PR_MESSAGE_CLASS, IPM_CONTACT);
- set_str_named_con_value (PidLidFileUnder, E_CONTACT_FILE_AS);
-
- set_str_con_value (PR_DISPLAY_NAME_UNICODE, E_CONTACT_FULL_NAME);
- set_str_con_value (PR_NORMALIZED_SUBJECT_UNICODE, E_CONTACT_FILE_AS);
- set_str_named_con_value (PidLidEmail1OriginalDisplayName, E_CONTACT_EMAIL_1);
- /*set_str_named_con_value (PidLidEmail1EmailAddress, E_CONTACT_EMAIL_1);*/
-
- /*set_str_con_value (0x8083001e, E_CONTACT_EMAIL_1);*/
- set_str_named_con_value (PidLidEmail2EmailAddress, E_CONTACT_EMAIL_2);
-
- set_str_named_con_value (PidLidEmail3EmailAddress, E_CONTACT_EMAIL_3);
- /*set_str_named_con_value (PidLidEmail3OriginalDisplayName, E_CONTACT_EMAIL_3);*/
-
- set_str_named_con_value (PidLidHtml, E_CONTACT_HOMEPAGE_URL);
- set_str_named_con_value (PidLidFreeBusyLocation, E_CONTACT_FREEBUSY_URL);
-
- set_str_con_value (PR_OFFICE_TELEPHONE_NUMBER_UNICODE, E_CONTACT_PHONE_BUSINESS);
- set_str_con_value (PR_HOME_TELEPHONE_NUMBER_UNICODE, E_CONTACT_PHONE_HOME);
- set_str_con_value (PR_MOBILE_TELEPHONE_NUMBER_UNICODE, E_CONTACT_PHONE_MOBILE);
- set_str_con_value (PR_HOME_FAX_NUMBER_UNICODE, E_CONTACT_PHONE_HOME_FAX);
- set_str_con_value (PR_BUSINESS_FAX_NUMBER_UNICODE, E_CONTACT_PHONE_BUSINESS_FAX);
- set_str_con_value (PR_PAGER_TELEPHONE_NUMBER_UNICODE, E_CONTACT_PHONE_PAGER);
- set_str_con_value (PR_ASSISTANT_TELEPHONE_NUMBER_UNICODE, E_CONTACT_PHONE_ASSISTANT);
- set_str_con_value (PR_COMPANY_MAIN_PHONE_NUMBER_UNICODE, E_CONTACT_PHONE_COMPANY);
-
- set_str_con_value (PR_MANAGER_NAME_UNICODE, E_CONTACT_MANAGER);
- set_str_con_value (PR_ASSISTANT_UNICODE, E_CONTACT_ASSISTANT);
- set_str_con_value (PR_COMPANY_NAME_UNICODE, E_CONTACT_ORG);
- set_str_con_value (PR_DEPARTMENT_NAME_UNICODE, E_CONTACT_ORG_UNIT);
- set_str_con_value (PR_PROFESSION_UNICODE, E_CONTACT_ROLE);
- set_str_con_value (PR_TITLE_UNICODE, E_CONTACT_TITLE);
-
- set_str_con_value (PR_OFFICE_LOCATION_UNICODE, E_CONTACT_OFFICE);
- set_str_con_value (PR_SPOUSE_NAME_UNICODE, E_CONTACT_SPOUSE);
-
- set_str_con_value (PR_BODY_UNICODE, E_CONTACT_NOTE);
- set_str_con_value (PR_NICKNAME_UNICODE, E_CONTACT_NICKNAME);
-
- /* BDAY AND ANNV */
- if (e_contact_get (mcd->contact, E_CONTACT_BIRTH_DATE)) {
- EContactDate *date = e_contact_get (mcd->contact, E_CONTACT_BIRTH_DATE);
- struct tm tmtime;
- time_t lt;
- NTTIME nt;
- struct FILETIME t;
-
- tmtime.tm_mday = date->day;
- tmtime.tm_mon = date->month - 1;
- tmtime.tm_year = date->year - 1900;
-
- lt = mktime (&tmtime);
- unix_to_nt_time (&nt, lt);
- t.dwLowDateTime = (nt << 32) >> 32;
- t.dwHighDateTime = (nt >> 32);
-
- if (!exchange_mapi_utils_add_spropvalue (mem_ctx, values, n_values, PR_BIRTHDAY, &t))
- return FALSE;
+ summary_file_name = ebbm_get_filename_from_uri (priv->book_uri, "cache.summary");
+ if (priv->summary)
+ g_object_unref (priv->summary);
+ priv->summary = e_book_backend_summary_new (summary_file_name, SUMMARY_FLUSH_TIMEOUT_SECS * 1000);
+
+ if (g_file_test (summary_file_name, G_FILE_TEST_EXISTS)) {
+ e_book_backend_summary_load (priv->summary);
}
- if (e_contact_get (mcd->contact, E_CONTACT_ANNIVERSARY)) {
- EContactDate *date = e_contact_get (mcd->contact, E_CONTACT_ANNIVERSARY);
- struct tm tmtime;
- time_t lt;
- NTTIME nt;
- struct FILETIME t;
+ if (priv->cache)
+ g_object_unref (priv->cache);
+ priv->cache = e_book_backend_cache_new (priv->book_uri);
- tmtime.tm_mday = date->day;
- tmtime.tm_mon = date->month - 1;
- tmtime.tm_year = date->year - 1900;
+ g_free (summary_file_name);
- lt = mktime (&tmtime);
- unix_to_nt_time (&nt, lt);
- t.dwLowDateTime = (nt << 32) >> 32;
- t.dwHighDateTime = (nt >> 32);
+ e_book_backend_set_is_loaded (E_BOOK_BACKEND (ebma), TRUE);
+ e_book_backend_set_is_writable (E_BOOK_BACKEND (ebma), FALSE);
+ e_book_backend_notify_writable (E_BOOK_BACKEND (ebma), FALSE);
- if (!exchange_mapi_utils_add_spropvalue (mem_ctx, values, n_values, PR_WEDDING_ANNIVERSARY, &t))
- return FALSE;
- }
+ ebbm_notify_connection_status (ebma, priv->mode != E_DATA_BOOK_MODE_LOCAL);
- /* Home and Office address */
- if (e_contact_get (mcd->contact, E_CONTACT_ADDRESS_HOME)) {
- EContactAddress *contact_addr = e_contact_get (mcd->contact, E_CONTACT_ADDRESS_HOME);
+ /* Either we are in Online mode or this is marked for offline */
+ if (priv->mode == E_DATA_BOOK_MODE_LOCAL &&
+ !priv->marked_for_offline) {
+ g_propagate_error (perror, EDB_ERROR (OFFLINE_UNAVAILABLE));
+ return;
+ }
- set_str_named_value (PidLidHomeAddress, contact_addr->street);
- set_str_value (PR_HOME_ADDRESS_POST_OFFICE_BOX_UNICODE, contact_addr->ext);
- set_str_value (PR_HOME_ADDRESS_CITY_UNICODE, contact_addr->locality);
- set_str_value (PR_HOME_ADDRESS_STATE_OR_PROVINCE_UNICODE, contact_addr->region);
- set_str_value (PR_HOME_ADDRESS_POSTAL_CODE_UNICODE, contact_addr->code);
- set_str_value (PR_HOME_ADDRESS_COUNTRY_UNICODE, contact_addr->country);
+ /* Once aunthentication in address book works this can be removed */
+ if (priv->mode == E_DATA_BOOK_MODE_LOCAL) {
+ return /* Success */;
}
+}
- if (e_contact_get (mcd->contact, E_CONTACT_ADDRESS_WORK)) {
- EContactAddress *contact_addr = e_contact_get (mcd->contact, E_CONTACT_ADDRESS_WORK);
+static void
+ebbm_remove (EBookBackendMAPI *ebma, GError **error)
+{
+ EBookBackendMAPIPrivate *priv;
+ gchar *filename;
- set_str_named_value (PidLidWorkAddress, contact_addr->street);
- set_str_value (PR_POST_OFFICE_BOX_UNICODE, contact_addr->ext);
- set_str_value (PR_LOCALITY_UNICODE, contact_addr->locality);
- set_str_value (PR_STATE_OR_PROVINCE_UNICODE, contact_addr->region);
- set_str_value (PR_POSTAL_CODE_UNICODE, contact_addr->code);
- set_str_value (PR_COUNTRY_UNICODE, contact_addr->country);
+ e_return_data_book_error_if_fail (ebma != NULL, E_DATA_BOOK_STATUS_INVALID_ARG);
+ e_return_data_book_error_if_fail (E_IS_BOOK_BACKEND_MAPI (ebma), E_DATA_BOOK_STATUS_INVALID_ARG);
+ e_return_data_book_error_if_fail (ebma->priv != NULL, E_DATA_BOOK_STATUS_INVALID_ARG);
+
+ priv = ebma->priv;
+
+ if (!priv->book_uri)
+ return;
+
+ e_book_backend_mapi_lock_connection (ebma);
+
+ if (priv->summary) {
+ g_object_unref (priv->summary);
+ priv->summary = NULL;
}
- if (e_contact_get (mcd->contact, E_CONTACT_IM_AIM)) {
- GList *l = e_contact_get (mcd->contact, E_CONTACT_IM_AIM);
- set_str_named_value (PidLidInstantMessagingAddress, l->data);
+ if (priv->cache) {
+ g_object_unref (priv->cache);
+ priv->cache = NULL;
}
- return TRUE;
+ filename = ebbm_get_filename_from_uri (priv->book_uri, "cache.summary");
+ if (g_file_test (filename, G_FILE_TEST_EXISTS))
+ g_unlink (filename);
+ g_free (filename);
+
+ filename = ebbm_get_filename_from_uri (priv->book_uri, "cache.xml");
+ if (g_file_test (filename, G_FILE_TEST_EXISTS))
+ g_unlink (filename);
+ g_free (filename);
+
+ e_book_backend_mapi_unlock_connection (ebma);
+}
+
+static gchar *
+ebbm_get_static_capabilities (EBookBackend *backend)
+{
+ return g_strdup ("net,bulk-removes,do-initial-query,contact-lists");
}
static void
-e_book_backend_mapi_create_contact (EBookBackend *backend,
- EDataBook *book,
- guint32 opid,
- const gchar *vcard )
+ebbm_get_required_fields (EBookBackendMAPI *ebma, GList **fields, GError **error)
{
- EContact *contact;
- gchar *id;
- mapi_id_t status;
- MapiCreateitemData mcd;
- EBookBackendMAPIPrivate *priv = ((EBookBackendMAPI *) backend)->priv;
- GError *mapi_error = NULL;
+ *fields = g_list_append (*fields, (gchar *) e_contact_field_name (E_CONTACT_FILE_AS));
+}
- if (enable_debug)
- printf("mapi create_contact \n");
+static void
+ebbm_get_supported_fields (EBookBackendMAPI *ebma, GList **fields, GError **error)
+{
+ gint i;
- switch (priv->mode) {
+ for (i = 0; i < G_N_ELEMENTS (mappings); i++) {
+ *fields = g_list_append (*fields, (gchar *)e_contact_field_name (mappings[i].field_id));
+ }
+
+ *fields = g_list_append (*fields, (gpointer) e_contact_field_name (E_CONTACT_BOOK_URI));
+}
+
+static void
+ebbm_authenticate_user (EBookBackendMAPI *ebma, const gchar *user, const gchar *passwd, const gchar *auth_method, GError **error)
+{
+ EBookBackendMAPIPrivate *priv = ebma->priv;
+ GError *mapi_error = NULL;
+ switch (priv->mode) {
case E_DATA_BOOK_MODE_LOCAL:
- e_data_book_respond_create(book, opid, EDB_ERROR (REPOSITORY_OFFLINE), NULL);
- break;
+ ebbm_notify_connection_status (ebma, FALSE);
+ return;
case E_DATA_BOOK_MODE_REMOTE:
- contact = e_contact_new_from_vcard(vcard);
- mcd.contact = contact;
- mcd.cache = priv->cache;
- status = exchange_mapi_connection_create_item (priv->conn, olFolderContacts, priv->fid,
- mapi_book_write_props, &mcd,
- NULL, NULL, NULL, 0, &mapi_error);
- if (!status) {
- GError *error = NULL;
+ if (priv->update_cache_thread) {
+ g_cancellable_cancel (priv->update_cache);
+ g_thread_join (priv->update_cache_thread);
+ priv->update_cache_thread = NULL;
+ }
+
+ e_book_backend_mapi_lock_connection (ebma);
+
+ if (priv->conn) {
+ g_object_unref (priv->conn);
+ priv->conn = NULL;
+ }
+
+ /* rather reuse already established connection */
+ priv->conn = exchange_mapi_connection_find (priv->profile);
+ if (priv->conn && !exchange_mapi_connection_connected (priv->conn))
+ exchange_mapi_connection_reconnect (priv->conn, passwd, &mapi_error);
+ else if (!priv->conn)
+ priv->conn = exchange_mapi_connection_new (priv->profile, passwd, &mapi_error);
- mapi_error_to_edb_error (&error, mapi_error, E_DATA_BOOK_STATUS_OTHER_ERROR, _("Failed to create item on a server"));
+ if (!priv->conn || mapi_error) {
+ if (priv->conn) {
+ g_object_unref (priv->conn);
+ priv->conn = NULL;
+ }
- e_data_book_respond_create (book, opid, error, NULL);
+ mapi_error_to_edb_error (error, mapi_error, E_DATA_BOOK_STATUS_OTHER_ERROR, _("Cannot connect"));
+ e_book_backend_mapi_unlock_connection (ebma);
if (mapi_error)
g_error_free (mapi_error);
+
+ ebbm_notify_connection_status (ebma, FALSE);
return;
}
- id = exchange_mapi_util_mapi_ids_to_uid (priv->fid, status);
- /* UID of the contact is nothing but the concatenated string of hex id of folder and the message.*/
- e_contact_set (contact, E_CONTACT_UID, id);
- e_contact_set (contact, E_CONTACT_BOOK_URI, priv->uri);
+ e_book_backend_mapi_unlock_connection (ebma);
- //somehow get the mid.
- //add to summary and cache.
- if (priv->marked_for_offline && priv->is_cache_ready)
- e_book_backend_cache_add_contact (priv->cache, contact);
+ ebbm_notify_connection_status (ebma, TRUE);
- if (priv->marked_for_offline && priv->is_summary_ready)
- e_book_backend_summary_add_contact (priv->summary, contact);
+ /* if (priv->marked_for_offline) */
+ priv->update_cache_thread = g_thread_create (ebbm_update_cache_cb, ebma, TRUE, NULL);
+ break;
- e_data_book_respond_create(book, opid, NULL /* Success */, contact);
+ default:
break;
}
}
static void
-e_book_backend_mapi_remove_contacts (EBookBackend *backend,
- EDataBook *book,
- guint32 opid,
- GList *id_list)
+ebbm_get_supported_auth_methods (EBookBackendMAPI *ebma, GList **auth_methods, GError **error)
{
- GSList *list=NULL;
- GList *tmp = id_list;
- EBookBackendMAPIPrivate *priv = ((EBookBackendMAPI *) backend)->priv;
- mapi_id_t fid, mid;
- GError *err = NULL;
+ *auth_methods = g_list_append (*auth_methods, g_strdup ("plain/password"));
+}
- if (enable_debug)
- printf("mapi: remove_contacts\n");
+static void
+ebbm_cancel_operation (EBookBackend *backend, EDataBook *book, GError **perror)
+{
+ EBookBackendMAPI *ebbm = E_BOOK_BACKEND_MAPI (backend);
- switch (priv->mode) {
+ if (!ebbm || !ebbm->priv || !ebbm->priv->op_queue || !em_operation_queue_cancel_all (ebbm->priv->op_queue))
+ g_propagate_error (perror, EDB_ERROR (COULD_NOT_CANCEL));
+}
- case E_DATA_BOOK_MODE_LOCAL:
- e_data_book_respond_remove_contacts (book, opid, EDB_ERROR (REPOSITORY_OFFLINE), NULL);
- break;
+static void
+ebbm_set_mode (EBookBackend *backend, EDataBookMode mode)
+{
+ EBookBackendMAPI *ebma = E_BOOK_BACKEND_MAPI (backend);
+ EBookBackendMAPIPrivate *priv = ebma->priv;
- case E_DATA_BOOK_MODE_REMOTE:
- while (tmp) {
- struct id_list *data = g_new (struct id_list, 1);
- exchange_mapi_util_mapi_ids_from_uid (tmp->data, &fid, &mid);
- data->id = mid;
- list = g_slist_prepend (list, (gpointer) data);
- tmp = tmp->next;
- }
+ priv->mode = mode;
+ if (e_book_backend_is_loaded (backend)) {
+ e_book_backend_mapi_lock_connection (ebma);
- exchange_mapi_connection_remove_items (priv->conn, olFolderContacts, priv->fid, 0, list, &err);
- if (priv->marked_for_offline && priv->is_cache_ready) {
- tmp = id_list;
- while (tmp) {
- e_book_backend_cache_remove_contact (priv->cache, tmp->data);
- tmp = tmp->next;
- }
- }
+ if (mode == E_DATA_BOOK_MODE_LOCAL) {
+ e_book_backend_notify_writable (backend, FALSE);
+ e_book_backend_set_is_writable (backend, FALSE);
+ ebbm_notify_connection_status (ebma, FALSE);
- if (priv->marked_for_offline && priv->is_summary_ready) {
- tmp = id_list;
- while (tmp) {
- e_book_backend_summary_remove_contact (priv->summary, tmp->data);
- tmp = tmp->next;
+ if (priv->conn) {
+ g_object_unref (priv->conn);
+ priv->conn = NULL;
}
+ } else if (mode == E_DATA_BOOK_MODE_REMOTE) {
+ ebbm_notify_connection_status (ebma, TRUE);
+ if (!priv->conn)
+ e_book_backend_notify_auth_required (backend);
}
- g_slist_free (list);
-
- if (err) {
- GError *mapi_err = err;
-
- err = NULL;
- mapi_error_to_edb_error (&err, mapi_err, E_DATA_BOOK_STATUS_OTHER_ERROR, NULL);
-
- g_error_free (mapi_err);
- }
-
- e_data_book_respond_remove_contacts (book, opid, err, id_list);
- break;
- default:
- break;
+ e_book_backend_mapi_unlock_connection (ebma);
}
}
static void
-e_book_backend_mapi_modify_contact (EBookBackend *backend,
- EDataBook *book,
- guint32 opid,
- const gchar *vcard)
+ebbm_get_contact (EBookBackendMAPI *ebma, const gchar *id, gchar **vcard, GError **error)
{
- EBookBackendMAPIPrivate *priv = ((EBookBackendMAPI *) backend)->priv;
- MapiCreateitemData mcd;
+ EBookBackendMAPIPrivate *priv;
EContact *contact;
- mapi_id_t fid, mid;
- gboolean status;
- gchar *tmp;
- GError *mapi_error = NULL;
- if (enable_debug)
- printf("mapi: modify_contacts\n");
+ g_return_if_fail (ebma != NULL);
+ g_return_if_fail (vcard != NULL);
- switch (priv->mode) {
+ priv = ebma->priv;
+ g_return_if_fail (priv != NULL);
- case E_DATA_BOOK_MODE_LOCAL:
- e_data_book_respond_modify (book, opid, EDB_ERROR (REPOSITORY_OFFLINE), NULL);
- break;
- case E_DATA_BOOK_MODE_REMOTE:
- contact = e_contact_new_from_vcard(vcard);
- tmp = e_contact_get (contact, E_CONTACT_UID);
- exchange_mapi_util_mapi_ids_from_uid (tmp, &fid, &mid);
- printf("modify id %s\n", tmp);
-
- mcd.contact = contact;
- mcd.cache = priv->cache;
- status = exchange_mapi_connection_modify_item (priv->conn, olFolderContacts, priv->fid, mid,
- mapi_book_write_props, &mcd,
- NULL, NULL, NULL, 0, &mapi_error);
- printf("getting %d\n", status);
- if (!status) {
- GError *perror = NULL;
-
- mapi_error_to_edb_error (&perror, mapi_error, E_DATA_BOOK_STATUS_OTHER_ERROR, _("Failed to modify item on a server"));
- e_data_book_respond_modify (book, opid, perror, NULL);
- if (mapi_error)
- g_error_free (mapi_error);
- break;
- }
+ if (!priv->cache) {
+ g_propagate_error (error, EDB_ERROR (REPOSITORY_OFFLINE));
+ return;
+ }
- e_contact_set (contact, E_CONTACT_BOOK_URI, priv->uri);
+ contact = e_book_backend_cache_get_contact (priv->cache, id);
+ if (contact) {
+ *vcard = e_vcard_to_string (E_VCARD (contact), EVC_FORMAT_VCARD_30);
+ g_object_unref (contact);
+ } else {
+ g_propagate_error (error, EDB_ERROR (CONTACT_NOT_FOUND));
+ }
+}
- //FIXME: Write it cleanly
- if (priv->marked_for_offline && priv->is_cache_ready)
- printf("delete cache %d\n", e_book_backend_cache_remove_contact (priv->cache, tmp));
+static void
+ebbm_get_contact_list (EBookBackendMAPI *ebma, const gchar *query, GList **vCards, GError **error)
+{
+ EBookBackendMAPIPrivate *priv;
+ GList *contacts, *l;
- if (priv->marked_for_offline && priv->is_summary_ready)
- e_book_backend_summary_remove_contact (priv->summary, tmp);
+ g_return_if_fail (ebma != NULL);
+ g_return_if_fail (query != NULL);
+ g_return_if_fail (vCards != NULL);
- if (priv->marked_for_offline && priv->is_cache_ready)
- e_book_backend_cache_add_contact (priv->cache, contact);
+ priv = ebma->priv;
+ g_return_if_fail (priv != NULL);
- if (priv->marked_for_offline && priv->is_summary_ready)
- e_book_backend_summary_add_contact (priv->summary, contact);
+ if (!priv->cache) {
+ g_propagate_error (error, EDB_ERROR (REPOSITORY_OFFLINE));
+ return;
+ }
+
+ contacts = e_book_backend_cache_get_contacts (priv->cache, query);
- e_data_book_respond_modify (book, opid, NULL /* Success */, contact);
+ for (l = contacts; l; l = g_list_next (l)) {
+ EContact *contact = l->data;
+ *vCards = g_list_prepend (*vCards, e_vcard_to_string (E_VCARD (contact), EVC_FORMAT_VCARD_30));
+
+ g_object_unref (contact);
}
+
+ g_list_free (contacts);
}
-static gboolean
-create_contact_item (FetchItemsCallbackData *item_data, gpointer data)
+struct BookViewThreadData
{
- EContact *contact;
- gchar *suid;
+ EBookBackendMAPI *ebma;
+ EDataBookView *book_view;
+};
- contact = mapi_book_utils_contact_from_props (item_data->conn, item_data->fid, item_data->properties, NULL);
- suid = exchange_mapi_util_mapi_ids_to_uid (item_data->fid, item_data->mid);
- printf("got contact %s\n", suid);
- if (contact) {
- /* UID of the contact is nothing but the concatenated string of hex id of folder and the message.*/
- e_contact_set (contact, E_CONTACT_UID, suid);
- data = contact;
+static gpointer
+ebbm_book_view_thread (gpointer data)
+{
+ struct BookViewThreadData *bvtd = data;
+ EBookBackendMAPIPrivate *priv;
+ GError *error = NULL;
+
+ g_return_val_if_fail (bvtd != NULL, NULL);
+ g_return_val_if_fail (bvtd->ebma != NULL, NULL);
+ g_return_val_if_fail (bvtd->book_view != NULL, NULL);
+
+ priv = bvtd->ebma->priv;
+
+ e_data_book_view_notify_status_message (bvtd->book_view, _("Searching"));
+
+ e_book_backend_mapi_update_view_by_cache (bvtd->ebma, bvtd->book_view, &error);
+
+ if (!error && priv && priv->conn && !priv->update_cache_thread
+ && e_book_backend_mapi_book_view_is_running (bvtd->ebma, bvtd->book_view)) {
+ EBookBackendMAPIClass *ebmac;
+
+ ebmac = E_BOOK_BACKEND_MAPI_GET_CLASS (bvtd->ebma);
+ if (ebmac && ebmac->op_book_view_thread)
+ ebmac->op_book_view_thread (bvtd->ebma, bvtd->book_view, &error);
+
+ if (!error && !priv->marked_for_offline) {
+ /* todo: create restriction based on the book_view */
+ ebbm_fetch_contacts (bvtd->ebma, NULL, bvtd->book_view, NULL, &error);
+ }
}
- g_free (suid);
+ /* do not stop book view when filling cache */
+ if (e_book_backend_mapi_book_view_is_running (bvtd->ebma, bvtd->book_view)
+ && (!priv->update_cache_thread || g_cancellable_is_cancelled (priv->update_cache)))
+ e_data_book_view_notify_complete (bvtd->book_view, error);
- return TRUE;
+ if (error)
+ g_error_free (error);
+
+ g_object_unref (bvtd->book_view);
+ g_object_unref (bvtd->ebma);
+ g_free (bvtd);
+
+ return NULL;
}
static void
-e_book_backend_mapi_get_contact (EBookBackend *backend,
- EDataBook *book,
- guint32 opid,
- const gchar *id)
+free_data_book_change (EDataBookChange *change)
{
- EBookBackendMAPIPrivate *priv = ((EBookBackendMAPI *) backend)->priv;
- EContact *contact = NULL;
- gchar *vcard;
- ESource *source;
- guint32 options = MAPI_OPTIONS_FETCH_ALL;
- gboolean is_public = FALSE;
-
- source = e_book_backend_get_source(backend);
- if (strcmp (e_source_get_property(source, "public"), "yes") == 0 ) {
- options |= MAPI_OPTIONS_USE_PFSTORE;
- is_public = TRUE;
+ if (change) {
+ g_free (change->vcard);
+ g_free (change);
}
+}
- if (enable_debug)
- printf("mapi: get_contact %s\n", id);
+/* Async OP functions, data structures and so on */
+
+typedef enum {
+ /* OP_LOAD_SOURCE, */
+ OP_REMOVE,
+
+ OP_CREATE_CONTACT,
+ OP_REMOVE_CONTACTS,
+ OP_MODIFY_CONTACT,
+ OP_GET_CONTACT,
+ OP_GET_CONTACT_LIST,
+ OP_START_BOOK_VIEW,
+ OP_STOP_BOOK_VIEW,
+ OP_GET_CHANGES,
+ OP_AUTHENTICATE_USER,
+ OP_GET_REQUIRED_FIELDS,
+ OP_GET_SUPPORTED_FIELDS,
+ OP_GET_SUPPORTED_AUTH_METHODS,
+} OperationType;
- switch (priv->mode) {
+typedef struct {
+ OperationType ot;
- case E_DATA_BOOK_MODE_LOCAL:
- contact = e_book_backend_cache_get_contact (priv->cache,
- id);
- if (contact) {
- vcard = e_vcard_to_string (E_VCARD (contact),
- EVC_FORMAT_VCARD_30);
- e_data_book_respond_get_contact (book,
- opid,
- NULL /* Success */,
- vcard);
- g_free (vcard);
- g_object_unref (contact);
- return;
+ EDataBook *book;
+ guint32 opid;
+} OperationBase;
+
+/* typedef struct {
+ OperationBase base;
+
+ ESource *source;
+ gboolean only_if_exists;
+} OperationLoadSource; */
+
+typedef struct {
+ OperationBase base;
+
+ gchar *user;
+ gchar *passwd;
+ gchar *auth_method;
+} OperationAuthenticateUser;
+
+typedef struct {
+ OperationBase base;
+
+ gchar *str;
+} OperationStr;
+
+typedef struct {
+ OperationBase base;
+
+ GList *id_list;
+} OperationIDList;
+
+typedef struct {
+ OperationBase base;
+
+ EDataBookView *book_view;
+} OperationBookView;
+
+static void
+ebbm_operation_cb (OperationBase *op, gboolean cancelled, EBookBackend *backend)
+{
+ EBookBackendMAPI *ebma;
+ EBookBackendMAPIClass *ebmac;
+ GError *error = NULL;
+
+ g_return_if_fail (backend != NULL);
+ g_return_if_fail (E_IS_BOOK_BACKEND (backend));
+ g_return_if_fail (op != NULL);
+
+ ebma = E_BOOK_BACKEND_MAPI (backend);
+ g_return_if_fail (ebma != NULL);
+
+ ebmac = E_BOOK_BACKEND_MAPI_GET_CLASS (ebma);
+ g_return_if_fail (ebmac != NULL);
+
+ switch (op->ot) {
+ /* it's a sync op by e_book_backend_open
+ case OP_LOAD_SOURCE: {
+ OperationLoadSource *opls = (OperationLoadSource *) op;
+
+ if (!cancelled) {
+ if (ebmac->op_load_source)
+ ebmac->op_load_source (ebma, opls->source, opls->only_if_exists, &error);
+ else
+ error = EDB_ERROR (NOT_SUPPORTED);
+
+ e_data_book_respond_open (op->book, op->opid, error);
}
- else {
- e_data_book_respond_get_contact (book, opid, EDB_ERROR (CONTACT_NOT_FOUND), "");
- return;
+
+ g_object_unref (opls->source);
+ } break; */
+ case OP_REMOVE: {
+ if (!cancelled) {
+ if (ebmac->op_remove)
+ ebmac->op_remove (ebma, &error);
+ else
+ error = EDB_ERROR (NOT_SUPPORTED);
+
+ e_data_book_respond_remove (op->book, op->opid, error);
}
+ } break;
+ case OP_CREATE_CONTACT: {
+ OperationStr *ops = (OperationStr *) op;
+ const gchar *vcard = ops->str;
- case E_DATA_BOOK_MODE_REMOTE:
+ if (!cancelled) {
+ EContact *contact = NULL;
- if (priv->marked_for_offline && e_book_backend_cache_is_populated (priv->cache)) {
- contact = e_book_backend_cache_get_contact (priv->cache,
- id);
- if (contact) {
- vcard = e_vcard_to_string (E_VCARD (contact),
- EVC_FORMAT_VCARD_30);
- e_data_book_respond_get_contact (book,
- opid,
- NULL /* Success */,
- vcard);
- g_free (vcard);
- g_object_unref (contact);
- return;
- }
- else {
- e_data_book_respond_get_contact (book, opid, EDB_ERROR (CONTACT_NOT_FOUND), "");
- return;
- }
+ if (ebmac->op_create_contact)
+ ebmac->op_create_contact (ebma, vcard, &contact, &error);
+ else
+ error = EDB_ERROR (NOT_SUPPORTED);
- } else {
- mapi_id_t fid, mid;
- GError *mapi_error = NULL;
-
- exchange_mapi_util_mapi_ids_from_uid (id, &fid, &mid);
- exchange_mapi_connection_fetch_item (priv->conn, priv->fid, mid,
- is_public ? NULL : mapi_book_utils_get_prop_list, GET_ALL_KNOWN_IDS,
- create_contact_item, contact,
- options, &mapi_error);
-
- if (contact) {
- e_contact_set (contact, E_CONTACT_BOOK_URI, priv->uri);
- vcard = e_vcard_to_string (E_VCARD (contact),
- EVC_FORMAT_VCARD_30);
- e_data_book_respond_get_contact (book,
- opid,
- NULL /* Success */,
- vcard);
- g_free (vcard);
+ if (contact && !error)
+ e_book_backend_mapi_notify_contact_update (ebma, NULL, contact, NULL, -1, -1, NULL);
+
+ e_data_book_respond_create (op->book, op->opid, error, contact);
+
+ if (contact)
g_object_unref (contact);
- return;
+ }
- } else {
- GError *err = NULL;
+ g_free (ops->str);
+ } break;
+ case OP_REMOVE_CONTACTS: {
+ OperationIDList *opil = (OperationIDList *) op;
- if (!mapi_error || mapi_error->code == MAPI_E_NOT_FOUND) {
- err = EDB_ERROR (CONTACT_NOT_FOUND);
- } else {
- mapi_error_to_edb_error (&err, mapi_error, E_DATA_BOOK_STATUS_CONTACT_NOT_FOUND, NULL);
- }
+ if (!cancelled) {
+ GList *removed_ids = NULL;
- e_data_book_respond_get_contact (book, opid, err, "");
+ if (ebmac->op_remove_contacts)
+ ebmac->op_remove_contacts (ebma, opil->id_list, &removed_ids, &error);
+ else
+ error = EDB_ERROR (NOT_SUPPORTED);
- if (mapi_error)
- g_error_free (mapi_error);
+ if (!error) {
+ GList *r;
- return;
+ for (r = removed_ids; r; r = r->next) {
+ const gchar *uid = r->data;
+
+ if (uid)
+ e_book_backend_mapi_notify_contact_removed (ebma, uid);
+ }
}
+
+ e_data_book_respond_remove_contacts (op->book, op->opid, error, removed_ids);
+
+ g_list_foreach (removed_ids, (GFunc) g_free, NULL);
+ g_list_free (removed_ids);
}
- default:
- break;
- }
+ g_list_foreach (opil->id_list, (GFunc) g_free, NULL);
+ g_list_free (opil->id_list);
+ } break;
+ case OP_MODIFY_CONTACT: {
+ OperationStr *ops = (OperationStr *) op;
+ const gchar *vcard = ops->str;
- return;
+ if (!cancelled) {
+ EContact *contact = NULL;
-}
+ if (ebmac->op_modify_contact)
+ ebmac->op_modify_contact (ebma, vcard, &contact, &error);
+ else
+ error = EDB_ERROR (NOT_SUPPORTED);
-static gboolean
-create_contact_list_cb (FetchItemsCallbackData *item_data, gpointer data)
-{
- struct mapi_SPropValue_array *array = item_data->properties;
- const mapi_id_t fid = item_data->fid;
- const mapi_id_t mid = item_data->mid;
+ if (contact && !error)
+ e_book_backend_mapi_notify_contact_update (ebma, NULL, contact, NULL, -1, -1, NULL);
- GList **listptr = data;
- EContact *contact;
- gchar *suid;
+ e_data_book_respond_modify (op->book, op->opid, error, contact);
- contact = mapi_book_utils_contact_from_props (item_data->conn, fid, array, NULL);
- suid = exchange_mapi_util_mapi_ids_to_uid (fid, mid);
+ if (contact)
+ g_object_unref (contact);
+ }
- if (contact) {
- /* UID of the contact is nothing but the concatenated string of hex id of folder and the message.*/
- printf("Contact added %s\n", suid);
- e_contact_set (contact, E_CONTACT_UID, suid);
-// e_contact_set (contact, E_CONTACT_BOOK_URI, priv->uri);
- //FIXME: Should we set this? How can we get this first?
- *listptr = g_list_prepend (*listptr, e_vcard_to_string (E_VCARD (contact), EVC_FORMAT_VCARD_30));
- g_object_unref (contact);
- }
+ g_free (ops->str);
+ } break;
+ case OP_GET_CONTACT: {
+ OperationStr *ops = (OperationStr *) op;
+ const gchar *id = ops->str;
- g_free (suid);
- return TRUE;
-}
+ if (!cancelled) {
+ gchar *vcard = NULL;
-static void
-e_book_backend_mapi_get_contact_list (EBookBackend *backend,
- EDataBook *book,
- guint32 opid,
- const gchar *query )
-{
- EBookBackendMAPIPrivate *priv = ((EBookBackendMAPI *) backend)->priv;
- ESource *source;
- guint32 options = MAPI_OPTIONS_FETCH_ALL;
- gboolean is_public = FALSE;
- source = e_book_backend_get_source(backend);
- if (strcmp (e_source_get_property(source, "public"), "yes") == 0 ) {
- options |= MAPI_OPTIONS_USE_PFSTORE;
- is_public = TRUE;
- }
+ if (ebmac->op_get_contact)
+ ebmac->op_get_contact (ebma, id, &vcard, &error);
+ else
+ error = EDB_ERROR (NOT_SUPPORTED);
- printf("mapi: get contact list %s\n", query);
- switch (priv->mode) {
- case E_DATA_BOOK_MODE_LOCAL:
- if (priv->marked_for_offline && priv->cache) {
- GList *contacts;
- GList *vcard_strings = NULL;
- GList *l;
+ e_data_book_respond_get_contact (op->book, op->opid, error, vcard);
- contacts = e_book_backend_cache_get_contacts (priv->cache, query);
+ g_free (vcard);
+ }
- for (l = contacts; l; l = g_list_next (l)) {
- EContact *contact = l->data;
- vcard_strings = g_list_prepend (vcard_strings, e_vcard_to_string (E_VCARD (contact),
- EVC_FORMAT_VCARD_30));
- g_object_unref (contact);
- }
+ g_free (ops->str);
+ } break;
+ case OP_GET_CONTACT_LIST: {
+ OperationStr *ops = (OperationStr *) op;
+ const gchar *query = ops->str;
- g_list_free (contacts);
- printf("get_contact_list in %s returning %d contacts\n", priv->uri, g_list_length (vcard_strings));
- e_data_book_respond_get_contact_list (book, opid, NULL /* Success */, vcard_strings);
- return;
+ if (!cancelled) {
+ GList *vCards = NULL;
+
+ if (ebmac->op_get_contact_list)
+ ebmac->op_get_contact_list (ebma, query, &vCards, &error);
+ else
+ error = EDB_ERROR (NOT_SUPPORTED);
+
+ e_data_book_respond_get_contact_list (op->book, op->opid, error, vCards);
+
+ /* respond freed them */
+ /* g_list_foreach (vCards, (GFunc) g_free, NULL); */
+ g_list_free (vCards);
}
- e_data_book_respond_get_contact_list (book, opid, EDB_ERROR (REPOSITORY_OFFLINE),
- NULL);
- return;
- case E_DATA_BOOK_MODE_REMOTE:
- printf("Mode : Remote\n");
- if (priv->marked_for_offline && priv->cache) {
- GList *contacts;
- GList *vcard_strings = NULL;
- GList *l;
-
- contacts = e_book_backend_cache_get_contacts (priv->cache, query);
-
- for (l = contacts; l;l = g_list_next (l)) {
- EContact *contact = l->data;
- vcard_strings = g_list_prepend (vcard_strings, e_vcard_to_string (E_VCARD (contact),
- EVC_FORMAT_VCARD_30));
- g_object_unref (contact);
+ g_free (ops->str);
+ } break;
+ case OP_START_BOOK_VIEW: {
+ OperationBookView *opbv = (OperationBookView *) op;
+
+ if (!cancelled && e_book_backend_mapi_book_view_is_running (ebma, opbv->book_view)) {
+ GError *err = NULL;
+ struct BookViewThreadData *bvtd = g_new0 (struct BookViewThreadData, 1);
+
+ bvtd->ebma = g_object_ref (ebma);
+ bvtd->book_view = g_object_ref (opbv->book_view);
+
+ g_thread_create (ebbm_book_view_thread, bvtd, FALSE, &err);
+
+ if (err) {
+ error = EDB_ERROR_EX (OTHER_ERROR, err->message);
+ e_data_book_view_notify_complete (opbv->book_view, error);
+ g_error_free (error);
+ g_error_free (err);
}
+ }
- g_list_free (contacts);
- printf("get_contact_list in %s returning %d contacts\n", priv->uri, g_list_length (vcard_strings));
- e_data_book_respond_get_contact_list (book, opid, NULL /* Success */, vcard_strings);
- return;
+ g_object_unref (opbv->book_view);
+ } break;
+ case OP_STOP_BOOK_VIEW: {
+ OperationBookView *opbv = (OperationBookView *) op;
+
+ if (!cancelled) {
+ e_data_book_view_notify_complete (opbv->book_view, NULL);
}
- else {
- GError *mapi_error = NULL;
- struct mapi_SRestriction res;
- GList *vcard_str = NULL;
- gboolean no_summary_search = g_ascii_strcasecmp (query, "(contains \"x-evolution-any-field\" \"\")") == 0;
-
- printf("Not marked for cache\n");
-
- /* Unfortunately MAPI Doesn't support searching well, we do allow only online search for emails rest all are returned as error. */
- if (!no_summary_search && !build_restriction_emails_contains (&res, query)) {
- e_data_book_respond_get_contact_list (book, opid, EDB_ERROR (OTHER_ERROR), NULL);
- return;
- }
- if (!exchange_mapi_connection_fetch_items (priv->conn, priv->fid, no_summary_search ? NULL : &res, NULL,
- is_public ? NULL : mapi_book_utils_get_prop_list, GET_ALL_KNOWN_IDS,
- create_contact_list_cb, &vcard_str,
- options, &mapi_error)) {
- GError *err = NULL;
+ g_object_unref (opbv->book_view);
+ } break;
+ case OP_GET_CHANGES: {
+ OperationStr *ops = (OperationStr *) op;
+ const gchar *change_id = ops->str;
- mapi_error_to_edb_error (&err, mapi_error, E_DATA_BOOK_STATUS_OTHER_ERROR, _("Failed to fetch items from a server"));
- e_data_book_respond_get_contact_list (book, opid, err, NULL);
+ if (!cancelled) {
+ GList *changes = NULL;
- if (mapi_error)
- g_error_free (mapi_error);
+ if (ebmac->op_get_changes)
+ ebmac->op_get_changes (ebma, change_id, &changes, &error);
+ else
+ error = EDB_ERROR (NOT_SUPPORTED);
- return;
- }
- printf("get_contact_list in %s returning %d contacts\n", priv->uri, g_list_length (vcard_str));
- e_data_book_respond_get_contact_list (book, opid, NULL /* Success */, vcard_str);
- return;
+ e_data_book_respond_get_changes (op->book, op->opid, error, changes);
+ g_list_foreach (changes, (GFunc) free_data_book_change, NULL);
+ g_list_free (changes);
}
- }
-}
-typedef struct {
- EBookBackendMAPI *bg;
- EDataBookView *book_view;
- gboolean stop;
-} BESearchClosure;
+ g_free (ops->str);
+ } break;
+ case OP_AUTHENTICATE_USER: {
+ OperationAuthenticateUser *opau = (OperationAuthenticateUser *) op;
-static BESearchClosure*
-init_closure (EDataBookView *book_view, EBookBackendMAPI *bg)
-{
- BESearchClosure *closure;
+ if (!cancelled) {
+ if (ebmac->op_authenticate_user)
+ ebmac->op_authenticate_user (ebma, opau->user, opau->passwd, opau->auth_method, &error);
+ else
+ error = EDB_ERROR (NOT_SUPPORTED);
- g_return_val_if_fail (bg != NULL, NULL);
- g_return_val_if_fail (bg->priv != NULL, NULL);
- g_return_val_if_fail (bg->priv->view_to_closure_hash != NULL, NULL);
-
- closure = g_new0 (BESearchClosure, 1);
- closure->bg = bg;
- closure->book_view = book_view;
- closure->stop = FALSE;
+ e_data_book_respond_authenticate_user (op->book, op->opid, error);
+ }
+
+ if (opau->passwd)
+ memset (opau->passwd, 0, strlen (opau->passwd));
+
+ g_free (opau->user);
+ g_free (opau->passwd);
+ g_free (opau->auth_method);
+ } break;
+ case OP_GET_REQUIRED_FIELDS: {
+ if (!cancelled) {
+ GList *fields = NULL;
+
+ if (ebmac->op_get_required_fields)
+ ebmac->op_get_required_fields (ebma, &fields, &error);
+ else
+ error = EDB_ERROR (NOT_SUPPORTED);
- g_hash_table_insert (bg->priv->view_to_closure_hash, g_object_ref (book_view), closure);
+ e_data_book_respond_get_required_fields (op->book, op->opid, error, fields);
+
+ /* do not free list data, only list itself */
+ g_list_free (fields);
+ }
+ } break;
+ case OP_GET_SUPPORTED_FIELDS: {
+ if (!cancelled) {
+ GList *fields = NULL;
+
+ if (ebmac->op_get_supported_fields)
+ ebmac->op_get_supported_fields (ebma, &fields, &error);
+ else
+ error = EDB_ERROR (NOT_SUPPORTED);
+
+ e_data_book_respond_get_supported_fields (op->book, op->opid, error, fields);
+
+ /* do not free list data, only list itself */
+ g_list_free (fields);
+ }
+ } break;
+ case OP_GET_SUPPORTED_AUTH_METHODS: {
+ if (!cancelled) {
+ GList *methods = NULL;
+
+ if (ebmac->op_get_supported_auth_methods)
+ ebmac->op_get_supported_auth_methods (ebma, &methods, &error);
+ else
+ error = EDB_ERROR (NOT_SUPPORTED);
+
+ e_data_book_respond_get_supported_auth_methods (op->book, op->opid, error, methods);
+
+ g_list_foreach (methods, (GFunc) g_free, NULL);
+ g_list_free (methods);
+ }
+ } break;
+ }
- return closure;
+ g_free (op);
}
static void
-destroy_closure (BESearchClosure *closure)
+base_op_abstract (EBookBackend *backend, EDataBook *book, guint32 opid, OperationType ot)
{
- g_return_if_fail (closure != NULL);
+ OperationBase *op;
+ EBookBackendMAPI *ebbm;
+ EBookBackendMAPIPrivate *priv;
+
+ g_return_if_fail (backend != NULL);
+ g_return_if_fail (E_IS_BOOK_BACKEND_MAPI (backend));
+
+ ebbm = E_BOOK_BACKEND_MAPI (backend);
+ priv = ebbm->priv;
+ g_return_if_fail (priv != NULL);
- if (closure->book_view)
- g_object_unref (closure->book_view);
- g_free (closure);
+ op = g_new0 (OperationBase, 1);
+ op->ot = ot;
+ op->book = book;
+ op->opid = opid;
+
+ em_operation_queue_push (priv->op_queue, op);
}
static void
-stop_book_view (EDataBookView *book_view, BESearchClosure *closure, EBookBackendMAPI *mapi_backend)
+str_op_abstract (EBookBackend *backend, EDataBook *book, guint32 opid, const gchar *str, OperationType ot)
{
- g_return_if_fail (closure != NULL);
+ OperationStr *op;
+ EBookBackendMAPI *ebbm;
+ EBookBackendMAPIPrivate *priv;
+
+ g_return_if_fail (backend != NULL);
+ g_return_if_fail (E_IS_BOOK_BACKEND_MAPI (backend));
+
+ ebbm = E_BOOK_BACKEND_MAPI (backend);
+ priv = ebbm->priv;
+ g_return_if_fail (priv != NULL);
+
+ op = g_new0 (OperationStr, 1);
+ op->base.ot = ot;
+ op->base.book = book;
+ op->base.opid = opid;
+ op->str = g_strdup (str);
+
+ em_operation_queue_push (priv->op_queue, op);
+}
+
+#define BASE_OP_DEF(_func, _ot) \
+static void \
+_func (EBookBackend *backend, EDataBook *book, guint32 opid) \
+{ \
+ base_op_abstract (backend, book, opid, _ot); \
+}
- closure->stop = TRUE;
+#define STR_OP_DEF(_func, _ot) \
+static void \
+_func (EBookBackend *backend, EDataBook *book, guint32 opid, const gchar *str) \
+{ \
+ str_op_abstract (backend, book, opid, str, _ot); \
}
+BASE_OP_DEF (ebbm_op_remove, OP_REMOVE)
+STR_OP_DEF (ebbm_op_create_contact, OP_CREATE_CONTACT)
+STR_OP_DEF (ebbm_op_modify_contact, OP_MODIFY_CONTACT)
+STR_OP_DEF (ebbm_op_get_contact, OP_GET_CONTACT)
+STR_OP_DEF (ebbm_op_get_contact_list, OP_GET_CONTACT_LIST)
+STR_OP_DEF (ebbm_op_get_changes, OP_GET_CHANGES)
+BASE_OP_DEF (ebbm_op_get_required_fields, OP_GET_REQUIRED_FIELDS)
+BASE_OP_DEF (ebbm_op_get_supported_fields, OP_GET_SUPPORTED_FIELDS)
+BASE_OP_DEF (ebbm_op_get_supported_auth_methods, OP_GET_SUPPORTED_AUTH_METHODS)
+
static void
-untrack_book_view (EBookBackendMAPI *mapi_backend, EDataBookView *book_view)
+ebbm_op_load_source (EBookBackend *backend, ESource *source, gboolean only_if_exists, GError **error)
{
- g_return_if_fail (mapi_backend != NULL);
- g_return_if_fail (mapi_backend->priv != NULL);
- g_return_if_fail (mapi_backend->priv->view_to_closure_hash != NULL);
- g_return_if_fail (book_view != NULL);
+ /*OperationLoadSource *op;*/
+ EBookBackendMAPI *ebbm;
+ EBookBackendMAPIPrivate *priv;
+ EBookBackendMAPIClass *ebmac;
+
+ g_return_if_fail (backend != NULL);
+ g_return_if_fail (E_IS_BOOK_BACKEND_MAPI (backend));
+ g_return_if_fail (source != NULL);
+
+ ebbm = E_BOOK_BACKEND_MAPI (backend);
+ priv = ebbm->priv;
+ g_return_if_fail (priv != NULL);
- g_hash_table_remove (mapi_backend->priv->view_to_closure_hash, book_view);
+ ebmac = E_BOOK_BACKEND_MAPI_GET_CLASS (ebbm);
+ g_return_if_fail (ebmac != NULL);
+
+ /* it's a sync op by e_book_backend_open
+ op = g_new0 (OperationLoadSource, 1);
+ op->base.ot = OP_LOAD_SOURCE;
+ op->base.book = book;
+ op->base.opid = opid;
+ op->source = g_object_ref (source);
+ op->only_if_exists = only_if_exists;
+
+ em_operation_queue_push (priv->op_queue, op);
+ */
+
+ if (ebmac->op_load_source)
+ ebmac->op_load_source (ebbm, source, only_if_exists, error);
+ else
+ g_propagate_error (error, EDB_ERROR (NOT_SUPPORTED));
}
static void
-get_contacts_from_cache (EBookBackendMAPI *ebmapi,
- const gchar *query,
- GPtrArray *ids,
- EDataBookView *book_view,
- BESearchClosure *closure)
+ebbm_op_remove_contacts (EBookBackend *backend, EDataBook *book, guint32 opid, GList *id_list)
{
- gint i;
+ OperationIDList *op;
+ EBookBackendMAPI *ebbm;
+ EBookBackendMAPIPrivate *priv;
+ GList *l;
- if (enable_debug)
- printf ("\nread contacts from cache for the ids found in summary\n");
- for (i = 0; i < ids->len; i ++) {
- gchar *uid;
- EContact *contact;
+ g_return_if_fail (backend != NULL);
+ g_return_if_fail (E_IS_BOOK_BACKEND_MAPI (backend));
+ g_return_if_fail (id_list != NULL);
- if (closure->stop)
- break;
+ ebbm = E_BOOK_BACKEND_MAPI (backend);
+ priv = ebbm->priv;
+ g_return_if_fail (priv != NULL);
- uid = g_ptr_array_index (ids, i);
- contact = e_book_backend_cache_get_contact (ebmapi->priv->cache, uid);
- if (contact) {
- e_data_book_view_notify_update (book_view, contact);
- g_object_unref (contact);
- }
+ op = g_new0 (OperationIDList, 1);
+ op->base.ot = OP_REMOVE_CONTACTS;
+ op->base.book = book;
+ op->base.opid = opid;
+ op->id_list = g_list_copy (id_list);
+
+ for (l = op->id_list; l; l = l->next) {
+ l->data = g_strdup (l->data);
}
+
+ em_operation_queue_push (priv->op_queue, op);
}
-static gboolean
-create_contact_cb (FetchItemsCallbackData *item_data, gpointer data)
+static void
+ebbm_op_start_book_view (EBookBackend *backend, EDataBookView *book_view)
{
- BESearchClosure *closure = data;
- EDataBookView *book_view = closure->book_view;
- EBookBackendMAPI *be = closure->bg;
- EContact *contact;
- EBookBackendMAPIPrivate *priv = ((EBookBackendMAPI *) be)->priv;
- gchar *suid;
+ OperationBookView *op;
+ EBookBackendMAPI *ebbm;
+ EBookBackendMAPIPrivate *priv;
- if (closure->stop)
- return FALSE;
+ g_return_if_fail (backend != NULL);
+ g_return_if_fail (E_IS_BOOK_BACKEND_MAPI (backend));
+ g_return_if_fail (book_view != NULL);
- contact = mapi_book_utils_contact_from_props (item_data->conn, item_data->fid, item_data->properties, NULL);
- suid = exchange_mapi_util_mapi_ids_to_uid (item_data->fid, item_data->mid);
+ ebbm = E_BOOK_BACKEND_MAPI (backend);
+ priv = ebbm->priv;
+ g_return_if_fail (priv != NULL);
- if (contact) {
- /* UID of the contact is nothing but the concatenated string of hex id of folder and the message.*/
- e_contact_set (contact, E_CONTACT_UID, suid);
- e_contact_set (contact, E_CONTACT_BOOK_URI, priv->uri);
- if (priv->cache)
- e_book_backend_cache_add_contact (priv->cache, contact);
- e_data_book_view_notify_update (book_view, contact);
- g_object_unref(contact);
- }
+ op = g_new0 (OperationBookView, 1);
+ op->base.ot = OP_START_BOOK_VIEW;
+ op->base.book = NULL;
+ op->base.opid = 0;
+ op->book_view = g_object_ref (book_view);
- g_free (suid);
- return TRUE;
+ g_hash_table_insert (priv->running_book_views, book_view, GINT_TO_POINTER(1));
+
+ em_operation_queue_push (priv->op_queue, op);
}
static void
-book_view_thread (gpointer data)
+ebbm_op_stop_book_view (EBookBackend *backend, EDataBookView *book_view)
{
- struct mapi_SRestriction res;
- struct mapi_SRestriction_or *or_res = NULL;
- BESearchClosure *closure = data;
- EDataBookView *book_view = closure->book_view;
- EBookBackendMAPI *backend = closure->bg;
- EBookBackendMAPIPrivate *priv = backend->priv;
- const gchar *query = NULL;
- GPtrArray *ids = NULL;
- GList *contacts = NULL, *temp_list = NULL;
- //Number of multiple restriction to apply
- guint res_count = 6;
- ESource *source;
- guint32 options = MAPI_OPTIONS_FETCH_ALL;
- gboolean is_public = FALSE;
- GError *err = NULL;
- GError *mapi_error = NULL;
+ OperationBookView *op;
+ EBookBackendMAPI *ebbm;
+ EBookBackendMAPIPrivate *priv;
- source = e_book_backend_get_source(E_BOOK_BACKEND(backend));
- if (strcmp (e_source_get_property(source, "public"), "yes") == 0 ) {
- options |= MAPI_OPTIONS_USE_PFSTORE;
- is_public = TRUE;
- }
+ g_return_if_fail (backend != NULL);
+ g_return_if_fail (E_IS_BOOK_BACKEND_MAPI (backend));
+ g_return_if_fail (book_view != NULL);
- if (enable_debug)
- printf("mapi: book view\n");
+ ebbm = E_BOOK_BACKEND_MAPI (backend);
+ priv = ebbm->priv;
+ g_return_if_fail (priv != NULL);
- e_data_book_view_notify_status_message (book_view, "Searching...");
- query = e_data_book_view_get_card_query (book_view);
+ op = g_new0 (OperationBookView, 1);
+ op->base.ot = OP_STOP_BOOK_VIEW;
+ op->base.book = NULL;
+ op->base.opid = 0;
+ op->book_view = g_object_ref (book_view);
- switch (priv->mode) {
+ g_hash_table_remove (priv->running_book_views, book_view);
- case E_DATA_BOOK_MODE_LOCAL:
- if (!priv->marked_for_offline) {
- err = EDB_ERROR (OFFLINE_UNAVAILABLE);
- e_data_book_view_notify_complete (book_view, err);
- g_error_free (err);
- untrack_book_view (backend, book_view);
- destroy_closure (closure);
- return;
- }
- if (!priv->cache) {
- printf("The cache is not yet built\n");
- e_data_book_view_notify_complete (book_view, NULL /* Success */);
- untrack_book_view (backend, book_view);
- destroy_closure (closure);
- return;
- }
+ em_operation_queue_push (priv->op_queue, op);
+}
- if (priv->is_summary_ready &&
- e_book_backend_summary_is_summary_query (priv->summary, query)) {
- if (enable_debug)
- printf ("reading the contacts from summary \n");
- ids = e_book_backend_summary_search (priv->summary, query);
- if (ids && ids->len > 0)
- get_contacts_from_cache (backend, query, ids, book_view, closure);
- if (ids)
- g_ptr_array_free (ids, TRUE);
- untrack_book_view (backend, book_view);
- destroy_closure (closure);
- return;
- }
+static void
+ebbm_op_authenticate_user (EBookBackend *backend, EDataBook *book, guint32 opid, const gchar *user, const gchar *passwd, const gchar *auth_method)
+{
+ OperationAuthenticateUser *op;
+ EBookBackendMAPI *ebbm;
+ EBookBackendMAPIPrivate *priv;
- /* fall back to cache */
- if (enable_debug)
- printf ("summary not found or a summary query reading the contacts from cache %s\n", query);
-
- contacts = e_book_backend_cache_get_contacts (priv->cache,
- query);
- temp_list = contacts;
- for (; contacts != NULL; contacts = g_list_next(contacts)) {
- if (closure->stop) {
- for (;contacts != NULL; contacts = g_list_next (contacts))
- g_object_unref (contacts->data);
- break;
- }
- e_data_book_view_notify_update (book_view,
- E_CONTACT(contacts->data));
- g_object_unref (contacts->data);
- }
- e_data_book_view_notify_complete (book_view, NULL /* Success */);
- if (temp_list)
- g_list_free (temp_list);
- untrack_book_view (backend, book_view);
- destroy_closure (closure);
- return;
+ g_return_if_fail (backend != NULL);
+ g_return_if_fail (E_IS_BOOK_BACKEND_MAPI (backend));
- case E_DATA_BOOK_MODE_REMOTE:
+ ebbm = E_BOOK_BACKEND_MAPI (backend);
+ priv = ebbm->priv;
+ g_return_if_fail (priv != NULL);
- if (!priv->conn || !exchange_mapi_connection_connected (priv->conn)) {
- e_book_backend_notify_auth_required (E_BOOK_BACKEND (backend));
- err = EDB_ERROR (AUTHENTICATION_REQUIRED);
- e_data_book_view_notify_complete (book_view, err);
- g_error_free (err);
- untrack_book_view (backend, book_view);
- destroy_closure (closure);
- return;
- }
+ op = g_new0 (OperationAuthenticateUser, 1);
+ op->base.ot = OP_AUTHENTICATE_USER;
+ op->base.book = book;
+ op->base.opid = opid;
+ op->user = g_strdup (user);
+ op->passwd = g_strdup (passwd);
+ op->auth_method = g_strdup (auth_method);
- if (priv->marked_for_offline && priv->cache && priv->is_cache_ready) {
- if (priv->is_summary_ready &&
- e_book_backend_summary_is_summary_query (priv->summary, query)) {
- if (enable_debug)
- printf ("reading the contacts from summary \n");
- ids = e_book_backend_summary_search (priv->summary, query);
- if (ids && ids->len > 0)
- get_contacts_from_cache (backend, query, ids, book_view, closure);
- if (ids)
- g_ptr_array_free (ids, TRUE);
- untrack_book_view (backend, book_view);
- destroy_closure (closure);
- return;
- }
+ em_operation_queue_push (priv->op_queue, op);
+}
- printf("Summary seems to be not there or not a summary query, lets fetch from cache directly\n");
+static void
+e_book_backend_mapi_init (EBookBackendMAPI *ebma)
+{
+ EBookBackendMAPIPrivate *priv;
- /* We are already cached. Lets return from there. */
- contacts = e_book_backend_cache_get_contacts (priv->cache,
- query);
- temp_list = contacts;
- for (; contacts != NULL; contacts = g_list_next(contacts)) {
- if (closure->stop) {
- for (;contacts != NULL; contacts = g_list_next (contacts))
- g_object_unref (contacts->data);
- break;
- }
- e_data_book_view_notify_update (book_view,
- E_CONTACT(contacts->data));
- g_object_unref (contacts->data);
- }
- e_data_book_view_notify_complete (book_view, NULL /* Success */);
- if (temp_list)
- g_list_free (temp_list);
- untrack_book_view (backend, book_view);
- destroy_closure (closure);
- return;
- }
+ priv = G_TYPE_INSTANCE_GET_PRIVATE (ebma, E_TYPE_BOOK_BACKEND_MAPI, EBookBackendMAPIPrivate);
- if (e_book_backend_summary_is_summary_query (priv->summary, query)) {
- /* free when done with or_res, not before */
- gchar *to_free = NULL;
+ /* Priv Struct init */
+ ebma->priv = priv;
- or_res = g_new0 (struct mapi_SRestriction_or, res_count);
+ priv->op_queue = em_operation_queue_new ((EMOperationQueueFunc) ebbm_operation_cb, ebma);
+ priv->running_book_views = g_hash_table_new (g_direct_hash, g_direct_equal);
+ priv->conn_lock = g_mutex_new ();
- if (!build_multiple_restriction_emails_contains (priv->conn, priv->fid, &res, or_res, query, &to_free)) {
- err = EDB_ERROR_EX (OTHER_ERROR, "Cannot build query based on email");
- e_data_book_view_notify_complete (book_view, err);
- g_error_free (err);
- g_free (or_res);
- g_free (to_free);
- untrack_book_view (backend, book_view);
- destroy_closure (closure);
- return;
- }
+ priv->update_cache = g_cancellable_new ();
+}
- //FIXME: We need to fetch only the query from the server live and not everything.
- if (!exchange_mapi_connection_fetch_items (priv->conn, priv->fid, &res, NULL,
- is_public ? NULL : mapi_book_utils_get_prop_list, GET_SHORT_SUMMARY,
- create_contact_cb, closure,
- options, &mapi_error)) {
- mapi_error_to_edb_error (&err, mapi_error, E_DATA_BOOK_STATUS_OTHER_ERROR, _("Failed to fetch items from a server"));
- e_data_book_view_notify_complete (book_view, err);
- g_error_free (err);
+static void
+ebbm_dispose (GObject *object)
+{
+ EBookBackendMAPI *ebma = E_BOOK_BACKEND_MAPI (object);
+ EBookBackendMAPIPrivate *priv = ebma->priv;
- if (mapi_error)
- g_error_free (mapi_error);
+ if (priv) {
+ if (priv->update_cache_thread) {
+ g_cancellable_cancel (priv->update_cache);
+ g_thread_join (priv->update_cache_thread);
+ priv->update_cache_thread = NULL;
+ }
- if (or_res)
- g_free(or_res);
- g_free (to_free);
- untrack_book_view (backend, book_view);
- destroy_closure (closure);
+ #define FREE(x) if (x) { g_free (x); x = NULL; }
+ #define UNREF(x) if (x) { g_object_unref (x); x = NULL; }
- return;
- }
+ e_book_backend_mapi_lock_connection (ebma);
+ UNREF (priv->conn);
+ e_book_backend_mapi_unlock_connection (ebma);
+ UNREF (priv->op_queue);
+ UNREF (priv->summary);
+ UNREF (priv->cache);
+ UNREF (priv->update_cache);
- g_free (to_free);
- } else {
- if (!exchange_mapi_connection_fetch_items (priv->conn, priv->fid, NULL, NULL,
- is_public ? NULL : mapi_book_utils_get_prop_list, GET_ALL_KNOWN_IDS,
- create_contact_cb, closure,
- options, &mapi_error)) {
- mapi_error_to_edb_error (&err, mapi_error, E_DATA_BOOK_STATUS_OTHER_ERROR, _("Failed to fetch items from a server"));
- e_data_book_view_notify_complete (book_view, err);
- g_error_free (err);
+ FREE (priv->profile);
+ FREE (priv->book_uri);
- if (mapi_error)
- g_error_free (mapi_error);
+ g_hash_table_destroy (priv->running_book_views);
+ g_mutex_free (priv->conn_lock);
- untrack_book_view (backend, book_view);
- destroy_closure (closure);
- return;
- }
- }
+ #undef UNREF
+ #undef FREE
- e_data_book_view_notify_complete (book_view, NULL /* Success */);
- default:
- break;
+ ebma->priv = NULL;
}
- if (or_res)
- g_free(or_res);
-
- untrack_book_view (backend, book_view);
- destroy_closure (closure);
+ /* Chain up to parent's dispose() method. */
+ if (G_OBJECT_CLASS (e_book_backend_mapi_parent_class)->dispose)
+ G_OBJECT_CLASS (e_book_backend_mapi_parent_class)->dispose (object);
}
static void
-e_book_backend_mapi_start_book_view (EBookBackend *backend,
- EDataBookView *book_view)
+e_book_backend_mapi_class_init (EBookBackendMAPIClass *klass)
{
- BESearchClosure *closure = init_closure (book_view, E_BOOK_BACKEND_MAPI (backend));
+ GObjectClass *object_class = G_OBJECT_CLASS (klass);
+ EBookBackendClass *backend_class = E_BOOK_BACKEND_CLASS (klass);
+
+ g_type_class_add_private (klass, sizeof (EBookBackendMAPIPrivate));
+
+ object_class->dispose = ebbm_dispose;
+
+ backend_class->load_source = ebbm_op_load_source;
+ backend_class->remove = ebbm_op_remove;
+ backend_class->get_static_capabilities = ebbm_get_static_capabilities;
+ backend_class->create_contact = ebbm_op_create_contact;
+ backend_class->remove_contacts = ebbm_op_remove_contacts;
+ backend_class->modify_contact = ebbm_op_modify_contact;
+ backend_class->get_contact = ebbm_op_get_contact;
+ backend_class->get_contact_list = ebbm_op_get_contact_list;
+ backend_class->start_book_view = ebbm_op_start_book_view;
+ backend_class->stop_book_view = ebbm_op_stop_book_view;
+ backend_class->get_changes = ebbm_op_get_changes;
+ backend_class->authenticate_user = ebbm_op_authenticate_user;
+ backend_class->get_required_fields = ebbm_op_get_required_fields;
+ backend_class->get_supported_fields = ebbm_op_get_supported_fields;
+ backend_class->get_supported_auth_methods = ebbm_op_get_supported_auth_methods;
+ backend_class->cancel_operation = ebbm_cancel_operation;
+ backend_class->set_mode = ebbm_set_mode;
+
+ klass->op_load_source = ebbm_load_source;
+ klass->op_remove = ebbm_remove;
+ klass->op_get_required_fields = ebbm_get_required_fields;
+ klass->op_get_supported_fields = ebbm_get_supported_fields;
+ klass->op_get_supported_auth_methods = ebbm_get_supported_auth_methods;
+ klass->op_authenticate_user = ebbm_authenticate_user;
+ klass->op_get_contact = ebbm_get_contact;
+ klass->op_get_contact_list = ebbm_get_contact_list;
+
+ klass->op_connection_status_changed = NULL;
+ klass->op_get_status_message = NULL;
+ klass->op_book_view_thread = NULL;
+ klass->op_fetch_contacts = NULL;
+ klass->op_fetch_known_uids = NULL;
+}
- g_return_if_fail (closure != NULL);
+gboolean
+e_book_backend_mapi_debug_enabled (void)
+{
+ gint8 debug_enabled = -1;
- if (enable_debug)
- printf ("mapi: start_book_view...\n");
+ if (debug_enabled == -1) {
+ if (g_getenv ("MAPI_DEBUG"))
+ debug_enabled = 1;
+ else
+ debug_enabled = 0;
+ }
- g_thread_create ((GThreadFunc) book_view_thread, closure, FALSE, NULL);
+ return debug_enabled != 0;
}
-static void
-e_book_backend_mapi_stop_book_view (EBookBackend *backend,
- EDataBookView *book_view)
+const gchar *
+e_book_backend_mapi_get_book_uri (EBookBackendMAPI *ebma)
{
- if (enable_debug)
- printf("mapi: stop book view\n");
+ g_return_val_if_fail (E_IS_BOOK_BACKEND_MAPI (ebma), NULL);
+ g_return_val_if_fail (ebma->priv != NULL, NULL);
- untrack_book_view (E_BOOK_BACKEND_MAPI (backend), book_view);
+ return ebma->priv->book_uri;
}
-static void
-e_book_backend_mapi_get_changes (EBookBackend *backend,
- EDataBook *book,
- guint32 opid,
- const gchar *change_id )
+void
+e_book_backend_mapi_lock_connection (EBookBackendMAPI *ebma)
{
- if (enable_debug)
- printf("mapi: get changes\n");
- /* FIXME : provide implmentation */
- e_data_book_respond_get_changes (book, opid, EDB_ERROR (NOT_SUPPORTED), NULL);
+ g_return_if_fail (E_IS_BOOK_BACKEND_MAPI (ebma));
+ g_return_if_fail (ebma->priv != NULL);
+ g_return_if_fail (ebma->priv->conn_lock != NULL);
+
+ g_mutex_lock (ebma->priv->conn_lock);
}
-static gboolean
-cache_contact_cb (FetchItemsCallbackData *item_data, gpointer data)
+void
+e_book_backend_mapi_unlock_connection (EBookBackendMAPI *ebma)
{
- EBookBackendMAPI *be = data;
- EContact *contact;
- EBookBackendMAPIPrivate *priv = ((EBookBackendMAPI *) be)->priv;
- gchar *suid;
+ g_return_if_fail (E_IS_BOOK_BACKEND_MAPI (ebma));
+ g_return_if_fail (ebma->priv != NULL);
+ g_return_if_fail (ebma->priv->conn_lock != NULL);
- contact = mapi_book_utils_contact_from_props (item_data->conn, item_data->fid, item_data->properties, NULL);
- suid = exchange_mapi_util_mapi_ids_to_uid (item_data->fid, item_data->mid);
+ g_mutex_unlock (ebma->priv->conn_lock);
+}
- if (contact) {
- /* UID of the contact is nothing but the concatenated string of hex id of folder and the message.*/
- e_contact_set (contact, E_CONTACT_UID, suid);
- e_contact_set (contact, E_CONTACT_BOOK_URI, priv->uri);
- e_book_backend_cache_add_contact (priv->cache, contact);
- e_book_backend_summary_add_contact (priv->summary, contact);
- g_object_unref(contact);
- }
+ExchangeMapiConnection *
+e_book_backend_mapi_get_connection (EBookBackendMAPI *ebma)
+{
+ g_return_val_if_fail (E_IS_BOOK_BACKEND_MAPI (ebma), NULL);
+ g_return_val_if_fail (ebma->priv != NULL, NULL);
- g_free (suid);
- return TRUE;
+ return ebma->priv->conn;
}
-static gpointer
-build_cache (EBookBackendMAPI *ebmapi)
+void
+e_book_backend_mapi_get_summary_and_cache (EBookBackendMAPI *ebma, EBookBackendSummary **summary, EBookBackendCache **cache)
{
- EBookBackendMAPIPrivate *priv = ((EBookBackendMAPI *) ebmapi)->priv;
- gchar *tmp;
- ESource *source;
- guint32 options = MAPI_OPTIONS_FETCH_ALL;
- gboolean is_public = FALSE;
+ g_return_if_fail (E_IS_BOOK_BACKEND_MAPI (ebma));
+ g_return_if_fail (ebma->priv != NULL);
- source = e_book_backend_get_source(E_BOOK_BACKEND(ebmapi));
- if (strcmp (e_source_get_property(source, "public"), "yes") == 0 ) {
- options |= MAPI_OPTIONS_USE_PFSTORE;
- is_public = TRUE;
- }
+ if (summary)
+ *summary = ebma->priv->summary;
- //FIXME: What if book view is NULL? Can it be? Check that.
- if (!priv->cache) {
- priv->cache = e_book_backend_cache_new (priv->uri);
- }
+ if (cache)
+ *cache = ebma->priv->cache;
+}
- e_file_cache_freeze_changes (E_FILE_CACHE (priv->cache));
+gboolean
+e_book_backend_mapi_book_view_is_running (EBookBackendMAPI *ebma, EDataBookView *book_view)
+{
+ g_return_val_if_fail (E_IS_BOOK_BACKEND_MAPI (ebma), FALSE);
+ g_return_val_if_fail (ebma->priv != NULL, FALSE);
- if (!exchange_mapi_connection_fetch_items (priv->conn, priv->fid, NULL, NULL,
- is_public ? NULL : mapi_book_utils_get_prop_list, GET_ALL_KNOWN_IDS,
- cache_contact_cb, ebmapi,
- options, NULL)) {
- printf("Error during caching addressbook\n");
- e_file_cache_thaw_changes (E_FILE_CACHE (priv->cache));
- return NULL;
- }
- tmp = g_strdup_printf("%d", (gint)time (NULL));
- e_book_backend_cache_set_time (priv->cache, tmp);
- printf("setting time %s\n", tmp);
- g_free (tmp);
- e_file_cache_thaw_changes (E_FILE_CACHE (priv->cache));
- e_book_backend_summary_save (priv->summary);
- priv->is_cache_ready = TRUE;
- priv->is_summary_ready = TRUE;
- return NULL;
+ return g_hash_table_lookup (ebma->priv->running_book_views, book_view) != NULL;
}
-#if 0
-static gpointer
-update_cache (EBookBackendMAPI *ebmapi)
+gboolean
+e_book_backend_mapi_is_marked_for_offline (EBookBackendMAPI *ebma)
{
- EBookBackendMAPIPrivate *priv = ((EBookBackendMAPI *) ebmapi)->priv;
- gchar *tmp = e_book_backend_cache_get_time (priv->cache);
- //FIXME: What if book view is NULL? Can it be? Check that.
- time_t t=0;
-// struct mapi_SRestriction res;
-
- if (tmp)
- t = atoi (tmp);
-
-// res.rt = RES_PROPERTY;
-// res.res.resProperty.relop = RES_PROPERTY;
-// res.res.resProperty.ulPropTag = PR_LAST_MODIFICATION_TIME;
-// res.res.resProperty.lpProp.ulPropTag = PR_LAST_MODIFICATION_TIME;
-// res.res.resProperty.lpProp.value.lpszA = email;
-
-#if 0
- printf("time updated was %d\n", t);
- /* Assume the cache and summary are already there */
-
- e_file_cache_freeze_changes (E_FILE_CACHE (priv->cache));
-
- if (!exchange_mapi_connection_fetch_items (priv->conn, priv->fid, &res, NULL,
- mapi_book_utils_get_prop_list, GET_ALL_KNOWN_IDS,
- cache_contact_cb, ebmapi,
- MAPI_OPTIONS_FETCH_ALL, NULL)) {
- printf("Error during caching addressbook\n");
- e_file_cache_thaw_changes (E_FILE_CACHE (priv->cache));
- return NULL;
- }
- e_file_cache_thaw_changes (E_FILE_CACHE (priv->cache));
- e_book_backend_summary_save (priv->summary);
- priv->is_cache_ready = TRUE;
- priv->is_summary_ready = TRUE;
-#endif
+ g_return_val_if_fail (E_IS_BOOK_BACKEND_MAPI (ebma), FALSE);
+ g_return_val_if_fail (ebma->priv != NULL, FALSE);
- return NULL;
+ return ebma->priv->marked_for_offline;
}
-#endif
-static void
-e_book_backend_mapi_authenticate_user (EBookBackend *backend,
- EDataBook *book,
- guint32 opid,
- const gchar *user,
- const gchar *passwd,
- const gchar *auth_method)
+void
+e_book_backend_mapi_update_view_by_cache (EBookBackendMAPI *ebma, EDataBookView *book_view, GError **error)
{
- EBookBackendMAPIPrivate *priv = ((EBookBackendMAPI *) backend)->priv;
- GError *mapi_error = NULL;
+ gint i;
+ const gchar *query = NULL;
+ EBookBackendCache *cache = NULL;
+ EBookBackendSummary *summary = NULL;
- if (enable_debug) {
- printf ("mapi: authenticate user\n");
- }
+ g_return_if_fail (ebma != NULL);
+ g_return_if_fail (E_IS_BOOK_BACKEND_MAPI (ebma));
+ g_return_if_fail (book_view != NULL);
+ g_return_if_fail (E_IS_DATA_BOOK_VIEW (book_view));
- switch (priv->mode) {
- case E_DATA_BOOK_MODE_LOCAL:
- e_book_backend_notify_writable (backend, FALSE);
- e_book_backend_notify_connection_status (backend, FALSE);
- e_data_book_respond_authenticate_user (book, opid, NULL /* Success */);
- return;
+ query = e_data_book_view_get_card_query (book_view);
+ e_book_backend_mapi_get_summary_and_cache (ebma, &summary, &cache);
- case E_DATA_BOOK_MODE_REMOTE:
- g_static_mutex_lock (&priv->running_mutex);
+ if (e_book_backend_summary_is_summary_query (summary, query)) {
+ GPtrArray *ids = NULL;
- /* rather reuse already established connection */
- priv->conn = exchange_mapi_connection_find (priv->profile);
- if (priv->conn && !exchange_mapi_connection_connected (priv->conn))
- exchange_mapi_connection_reconnect (priv->conn, passwd, &mapi_error);
- else if (!priv->conn)
- priv->conn = exchange_mapi_connection_new (priv->profile, passwd, &mapi_error);
+ ids = e_book_backend_summary_search (summary, query);
+ if (ids) {
+ for (i = 0; i < ids->len; i ++) {
+ gchar *uid;
+ EContact *contact;
- if (!priv->conn || mapi_error) {
- GError *err = NULL;
+ if (i > 0 && (i % 10) == 0 && !e_book_backend_mapi_book_view_is_running (ebma, book_view))
+ break;
- if (priv->conn) {
- g_object_unref (priv->conn);
- priv->conn = NULL;
+ uid = g_ptr_array_index (ids, i);
+ contact = e_book_backend_cache_get_contact (cache, uid);
+ if (contact) {
+ e_data_book_view_notify_update (book_view, contact);
+ g_object_unref (contact);
+ }
}
-
- mapi_error_to_edb_error (&err, mapi_error, E_DATA_BOOK_STATUS_OTHER_ERROR, _("Cannot connect"));
- e_data_book_respond_authenticate_user (book, opid, err);
- g_static_mutex_unlock (&priv->running_mutex);
- if (mapi_error)
- g_error_free (mapi_error);
- return;
+ g_ptr_array_free (ids, TRUE);
}
+ } else {
+ GList *contacts = NULL, *c;
- if (priv->cache && priv->is_cache_ready) {
- printf("FIXME: Should check for an update in the cache\n");
-// g_thread_create ((GThreadFunc) update_cache,
- // backend, FALSE, backend);
- } else if (priv->marked_for_offline && !priv->is_cache_ready) {
- /* Means we dont have a cache. Lets build that first */
- printf("Preparing to build cache\n");
- g_thread_create ((GThreadFunc) build_cache, backend, FALSE, NULL);
+ contacts = e_book_backend_cache_get_contacts (cache, query);
+ for (c = contacts, i = 0; c != NULL; c = g_list_next (c), i++) {
+ if (i > 0 && (i % 10) == 0 && !e_book_backend_mapi_book_view_is_running (ebma, book_view))
+ break;
+
+ e_data_book_view_notify_update (book_view, E_CONTACT (c->data));
}
- e_book_backend_set_is_writable (backend, TRUE);
- e_data_book_respond_authenticate_user (book, opid, NULL /* Success */);
- g_static_mutex_unlock (&priv->running_mutex);
- return;
- default :
- break;
+ g_list_foreach (contacts, (GFunc) g_object_unref, NULL);
+ g_list_free (contacts);
}
}
-static void
-e_book_backend_mapi_get_required_fields (EBookBackend *backend,
- EDataBook *book,
- guint32 opid)
+static glong
+get_current_time_ms (void)
{
- GList *fields = NULL;
+ GTimeVal tv;
- if (enable_debug)
- printf ("mapi get_required_fields...\n");
+ g_get_current_time (&tv);
- fields = g_list_append (fields, (gchar *)e_contact_field_name (E_CONTACT_FILE_AS));
- e_data_book_respond_get_supported_fields (book, opid,
- NULL /* Success */,
- fields);
- g_list_free (fields);
+ return tv.tv_sec * 1000 + tv.tv_usec / 1000;
}
-static void
-e_book_backend_mapi_get_supported_fields (EBookBackend *backend,
- EDataBook *book,
- guint32 opid)
+/* called from op_fetch_contacts - book_view and notify_contact_data are taken from there;
+ notify_contact_data is a pointer to FetchContactsData, if not NULL;
+ returns whether can continue with fetching */
+gboolean
+e_book_backend_mapi_notify_contact_update (EBookBackendMAPI *ebma, EDataBookView *pbook_view, EContact *contact, const struct timeval *pr_last_modification_time, gint index, gint total, gpointer notify_contact_data)
{
- GList *fields;
+ EBookBackendMAPIPrivate *priv;
+ struct FetchContactsData *fcd = notify_contact_data;
+ EDataBookView *book_view = pbook_view;
- if (enable_debug)
- printf ("mapi get_supported_fields...\n");
+ g_return_val_if_fail (E_IS_BOOK_BACKEND_MAPI (ebma), FALSE);
+ g_return_val_if_fail (ebma->priv, FALSE);
+ g_return_val_if_fail (contact != NULL, FALSE);
- fields = mapi_book_utils_get_supported_fields ();
- e_data_book_respond_get_supported_fields (book, opid,
- NULL /* Success */,
- fields);
- g_list_free (fields);
+ priv = ebma->priv;
+ g_return_val_if_fail (priv != NULL, FALSE);
-}
+ /* report progres to any book_view, if not passed in;
+ it can happen when cache is filling and the book view started later */
+ if (!book_view)
+ book_view = ebbm_pick_book_view (ebma);
-static void
-e_book_backend_mapi_get_supported_auth_methods (EBookBackend *backend, EDataBook *book, guint32 opid)
-{
- GList *auth_methods = NULL;
- gchar *auth_method;
+ if (book_view) {
+ guint32 current_time;
- if (enable_debug)
- printf ("mapi get_supported_auth_methods...\n");
-
- auth_method = g_strdup_printf ("plain/password");
- auth_methods = g_list_append (auth_methods, auth_method);
- e_data_book_respond_get_supported_auth_methods (book,
- opid,
- NULL /* Success */,
- auth_methods);
- g_free (auth_method);
- g_list_free (auth_methods);
-}
+ if (!e_book_backend_mapi_book_view_is_running (ebma, book_view))
+ return FALSE;
-static void
-e_book_backend_mapi_cancel_operation (EBookBackend *backend, EDataBook *book, GError **perror)
-{
- if (enable_debug)
- printf ("mapi cancel_operation...\n");
- g_propagate_error (perror, EDB_ERROR (COULD_NOT_CANCEL));
-}
+ current_time = get_current_time_ms ();
+ if (index > 0 && fcd && current_time - fcd->last_notification > 333) {
+ gchar *status_msg = NULL;
+ EBookBackendMAPIClass *ebmac = E_BOOK_BACKEND_MAPI_GET_CLASS (ebma);
-static void
-e_book_backend_mapi_remove (EBookBackend *backend,
- EDataBook *book,
- guint32 opid)
-{
- EBookBackendMAPIPrivate *priv = ((EBookBackendMAPI *) backend)->priv;
- gchar *cache_uri = NULL;
- gboolean status = TRUE;
- ESource *source;
- GError *mapi_error = NULL;
+ if (ebmac->op_get_status_message)
+ status_msg = ebmac->op_get_status_message (ebma, index, total);
- source = e_book_backend_get_source (backend);
+ if (status_msg)
+ e_data_book_view_notify_status_message (book_view, status_msg);
- if (enable_debug)
- printf("mapi: remove\n");
+ g_free (status_msg);
- switch (priv->mode) {
+ fcd->last_notification = current_time;
+ }
+ }
- case E_DATA_BOOK_MODE_LOCAL:
- e_data_book_respond_remove (book, opid, EDB_ERROR (OFFLINE_UNAVAILABLE));
- return;
+ if (!pbook_view && g_cancellable_is_cancelled (priv->update_cache))
+ return FALSE;
- case E_DATA_BOOK_MODE_REMOTE:
-
- if (strcmp (e_source_get_property(source, "public"), "yes") != 0)
- status = exchange_mapi_connection_remove_folder (priv->conn, priv->fid, 0, &mapi_error);
-
- if (!status) {
- GError *err = NULL;
+ e_book_backend_cache_add_contact (ebma->priv->cache, contact);
+ e_book_backend_summary_add_contact (ebma->priv->summary, contact);
+ e_book_backend_notify_update (E_BOOK_BACKEND (ebma), contact);
- if (mapi_error) {
- mapi_error_to_edb_error (&err, mapi_error, E_DATA_BOOK_STATUS_OTHER_ERROR, _("Failed to remove public folder"));
- g_error_free (mapi_error);
- } else {
- err = EDB_ERROR (OTHER_ERROR);
- }
+ if (fcd && pr_last_modification_time) {
+ if (fcd->last_modification < pr_last_modification_time->tv_sec)
+ fcd->last_modification = pr_last_modification_time->tv_sec;
+ }
- e_data_book_respond_remove (book, opid, err);
- return;
- }
+ return TRUE;
+}
- if (priv->marked_for_offline && priv->is_summary_ready) {
- g_object_unref (priv->summary);
- priv->summary = NULL;
- }
+void
+e_book_backend_mapi_notify_contact_removed (EBookBackendMAPI *ebma, const gchar *uid)
+{
+ EBookBackendMAPIPrivate *priv;
- if (e_book_backend_cache_exists (priv->uri)) {
+ g_return_if_fail (E_IS_BOOK_BACKEND_MAPI (ebma));
+ g_return_if_fail (ebma->priv);
+ g_return_if_fail (uid != NULL);
- g_object_unref (priv->cache);
- priv->cache= NULL;
+ priv = ebma->priv;
+ g_return_if_fail (priv != NULL);
- }
+ e_book_backend_cache_remove_contact (priv->cache, uid);
+ e_book_backend_summary_remove_contact (priv->summary, uid);
+ e_book_backend_notify_remove (E_BOOK_BACKEND (ebma), uid);
+}
- /* Remove the summary and cache independent of whether they are loaded or not. */
- cache_uri = get_filename_from_uri (priv->uri, "cache.summary");
- if (g_file_test (cache_uri, G_FILE_TEST_EXISTS)) {
- g_unlink (cache_uri);
- }
- g_free (cache_uri);
+/* utility functions/macros */
- cache_uri = get_filename_from_uri (priv->uri, "cache.xml");
- if (g_file_test (cache_uri, G_FILE_TEST_EXISTS)) {
- g_unlink (cache_uri);
- }
- g_free (cache_uri);
+/* 'data' is one of GET_ALL_KNOWN_IDS or GET_UIDS_ONLY */
+gboolean
+mapi_book_utils_get_prop_list (ExchangeMapiConnection *conn, mapi_id_t fid, TALLOC_CTX *mem_ctx, struct SPropTagArray *props, gpointer data)
+{
+ /* this is a list of all known book MAPI tag IDs;
+ if you add new add it here too, otherwise it may not be fetched */
+ static uint32_t known_book_mapi_ids[] = {
+ PR_ASSISTANT_TELEPHONE_NUMBER_UNICODE,
+ PR_ASSISTANT_UNICODE,
+ PR_BIRTHDAY,
+ PR_BODY,
+ PR_BODY_UNICODE,
+ PR_BUSINESS_FAX_NUMBER_UNICODE,
+ PR_COMPANY_MAIN_PHONE_NUMBER_UNICODE,
+ PR_COMPANY_NAME_UNICODE,
+ PR_COUNTRY_UNICODE,
+ PR_DEPARTMENT_NAME_UNICODE,
+ PR_DISPLAY_NAME_UNICODE,
+ PR_EMAIL_ADDRESS_UNICODE,
+ PR_SMTP_ADDRESS_UNICODE, /* used in GAL */
+ PR_FID,
+ PR_GIVEN_NAME_UNICODE,
+ PR_HASATTACH,
+ PR_HOME_ADDRESS_CITY_UNICODE,
+ PR_HOME_ADDRESS_COUNTRY_UNICODE,
+ PR_HOME_ADDRESS_POSTAL_CODE_UNICODE,
+ PR_HOME_ADDRESS_POST_OFFICE_BOX_UNICODE,
+ PR_HOME_ADDRESS_STATE_OR_PROVINCE_UNICODE,
+ PR_HOME_FAX_NUMBER_UNICODE,
+ PR_HOME_TELEPHONE_NUMBER_UNICODE,
+ PR_INSTANCE_NUM,
+ PR_INST_ID,
+ PR_LAST_MODIFICATION_TIME,
+ PR_LOCALITY_UNICODE,
+ PR_MANAGER_NAME_UNICODE,
+ PR_MESSAGE_CLASS,
+ PR_MID,
+ PR_MOBILE_TELEPHONE_NUMBER_UNICODE,
+ PR_NICKNAME_UNICODE,
+ PR_NORMALIZED_SUBJECT_UNICODE,
+ PR_OFFICE_LOCATION_UNICODE,
+ PR_OFFICE_TELEPHONE_NUMBER_UNICODE,
+ PR_PAGER_TELEPHONE_NUMBER_UNICODE,
+ PR_POSTAL_CODE_UNICODE,
+ PR_POST_OFFICE_BOX_UNICODE,
+ PR_PROFESSION_UNICODE,
+ PR_RULE_MSG_NAME,
+ PR_RULE_MSG_PROVIDER,
+ PR_SPOUSE_NAME_UNICODE,
+ PR_STATE_OR_PROVINCE_UNICODE,
+ PR_SUBJECT_UNICODE,
+ PR_SURNAME_UNICODE,
+ PR_TITLE_UNICODE,
+ PR_WEDDING_ANNIVERSARY,
+ PROP_TAG(PT_UNICODE, 0x801f)
+ };
- e_data_book_respond_remove (book, opid, NULL /* Success */);
- return;
+ static uint32_t uids_only_ids[] = {
+ PR_FID,
+ PR_MID,
+ PR_EMAIL_ADDRESS_UNICODE
+ };
+
+ /* do not make this array static, the function modifies it on run */
+ ResolveNamedIDsData nids[] = {
+ { PidLidDistributionListName, 0 },
+ { PidLidDistributionListOneOffMembers, 0 },
+ { PidLidDistributionListMembers, 0 },
+ { PidLidDistributionListChecksum, 0 },
- default:
- break;
- }
+ { PidLidFileUnder, 0 },
- return;
+ { PidLidEmail1OriginalDisplayName, 0 },
+ { PidLidEmail2OriginalDisplayName, 0 },
+ { PidLidEmail3OriginalDisplayName, 0 },
+ { PidLidInstantMessagingAddress, 0 },
+ { PidLidHtml, 0 },
+ { PidLidFreeBusyLocation, 0 }
+ };
+
+ g_return_val_if_fail (props != NULL, FALSE);
+
+ if (data == GET_UIDS_ONLY)
+ return exchange_mapi_utils_add_props_to_props_array (mem_ctx, props, uids_only_ids, G_N_ELEMENTS (uids_only_ids));
- /* FIXME : provide implmentation */
+ if (data == GET_ALL_KNOWN_IDS && !exchange_mapi_utils_add_props_to_props_array (mem_ctx, props, known_book_mapi_ids, G_N_ELEMENTS (known_book_mapi_ids)))
+ return FALSE;
+
+ /* called with fid = 0 from GAL */
+ if (!fid)
+ fid = exchange_mapi_connection_get_default_folder_id (conn, olFolderContacts, NULL);
+
+ return exchange_mapi_utils_add_named_ids_to_props_array (conn, fid, mem_ctx, props, nids, G_N_ELEMENTS (nids));
}
-static void
-e_book_backend_mapi_set_mode (EBookBackend *backend, EDataBookMode mode)
+static gchar *
+bin_to_string (const uint8_t *lpb, uint32_t cb)
{
- EBookBackendMAPIPrivate *priv = ((EBookBackendMAPI *) backend)->priv;
+ gchar *res, *p;
+ uint32_t i;
- if (enable_debug)
- printf("mapi: set_mode \n");
+ g_return_val_if_fail (lpb != NULL, NULL);
+ g_return_val_if_fail (cb > 0, NULL);
- priv->mode = mode;
- if (e_book_backend_is_loaded (backend)) {
- if (mode == E_DATA_BOOK_MODE_LOCAL) {
- e_book_backend_notify_writable (backend, FALSE);
- e_book_backend_notify_connection_status (backend, FALSE);
- /* FIXME: Uninitialize mapi here. may be.*/
- }
- else if (mode == E_DATA_BOOK_MODE_REMOTE) {
- e_book_backend_notify_writable (backend, TRUE);
- e_book_backend_notify_connection_status (backend, TRUE);
- e_book_backend_notify_auth_required (backend); //FIXME: WTH is this required.
- }
+ res = g_new0 (gchar, cb * 2 + 1);
+ for (i = 0, p = res; i < cb; i++, p += 2) {
+ sprintf (p, "%02x", lpb[i] & 0xFF);
}
+
+ return res;
}
-static void
-e_book_backend_mapi_init (EBookBackendMAPI *backend)
+static const gchar *
+not_null (gconstpointer ptr)
{
- EBookBackendMAPIPrivate *priv;
+ return ptr ? (const gchar *) ptr : "";
+}
- priv = g_new0 (EBookBackendMAPIPrivate, 1);
- /* Priv Struct init */
- backend->priv = priv;
+/* This is not setting E_CONTACT_UID */
+EContact *
+mapi_book_utils_contact_from_props (ExchangeMapiConnection *conn, mapi_id_t fid, const gchar *book_uri, struct mapi_SPropValue_array *mapi_properties, struct SRow *aRow)
+{
+ EContact *contact = e_contact_new ();
+ gint i;
- priv->view_to_closure_hash = g_hash_table_new (g_direct_hash, g_direct_equal);
- priv->summary = NULL;
+ if (book_uri)
+ e_contact_set (contact, E_CONTACT_BOOK_URI, book_uri);
- priv->marked_for_offline = FALSE;
- priv->uri = NULL;
- priv->cache = NULL;
- priv->is_summary_ready = FALSE;
- priv->is_cache_ready = FALSE;
- g_static_mutex_init (&priv->running_mutex);
+ #define get_proptag(proptag) (aRow ? exchange_mapi_util_find_row_propval (aRow, proptag) : exchange_mapi_util_find_array_propval (mapi_properties, proptag))
+ #define get_str_proptag(proptag) not_null (get_proptag (proptag))
+ #define get_namedid(nid) (aRow ? exchange_mapi_util_find_row_namedid (aRow, conn, fid, nid) : exchange_mapi_util_find_array_namedid (mapi_properties, conn, fid, nid))
+ #define get_str_namedid(nid) not_null (get_namedid (nid))
- if (g_getenv ("MAPI_DEBUG"))
- enable_debug = TRUE;
- else
- enable_debug = FALSE;
+ if (g_str_equal (get_str_proptag (PR_MESSAGE_CLASS), IPM_DISTLIST)) {
+ const struct mapi_SBinaryArray *members, *members_dlist;
+ GSList *attrs = NULL, *a;
+ gint i;
-}
+ /* it's a contact list/distribution list, fetch members and return it */
+ e_contact_set (contact, E_CONTACT_IS_LIST, GINT_TO_POINTER (TRUE));
+ /* we do not support this option, same as GroupWise */
+ e_contact_set (contact, E_CONTACT_LIST_SHOW_ADDRESSES, GINT_TO_POINTER (TRUE));
-static void
-e_book_backend_mapi_dispose (GObject *object)
-{
- EBookBackendMAPI *mapi_backend = E_BOOK_BACKEND_MAPI (object);
- EBookBackendMAPIPrivate *priv = mapi_backend->priv;
+ e_contact_set (contact, E_CONTACT_FILE_AS, get_str_namedid (PidLidDistributionListName));
- if (priv) {
- if (priv->view_to_closure_hash) {
- g_hash_table_foreach (priv->view_to_closure_hash, (GHFunc) stop_book_view, mapi_backend);
- g_hash_table_destroy (priv->view_to_closure_hash);
- priv->view_to_closure_hash = NULL;
+ members = get_namedid (PidLidDistributionListOneOffMembers);
+ members_dlist = get_namedid (PidLidDistributionListMembers);
+
+ g_return_val_if_fail (members != NULL, NULL);
+ g_return_val_if_fail (members_dlist != NULL, NULL);
+
+ /* these two lists should be in sync */
+ g_return_val_if_fail (members_dlist->cValues == members->cValues, NULL);
+
+ for (i = 0; i < members->cValues; i++) {
+ struct Binary_r br;
+ gchar *display_name = NULL, *email = NULL;
+ gchar *str;
+
+ br.lpb = members->bin[i].lpb;
+ br.cb = members->bin[i].cb;
+ if (exchange_mapi_util_entryid_decode_oneoff (&br, &display_name, &email)) {
+ EVCardAttribute *attr;
+ gchar *value;
+ CamelInternetAddress *addr;
+
+ addr = camel_internet_address_new ();
+ attr = e_vcard_attribute_new (NULL, EVC_EMAIL);
+
+ camel_internet_address_add (addr, display_name, email);
+
+ value = camel_address_encode (CAMEL_ADDRESS (addr));
+
+ if (value)
+ e_vcard_attribute_add_value (attr, value);
+
+ g_free (value);
+ g_object_unref (addr);
+
+ str = g_strdup_printf ("%d", i + 1);
+ e_vcard_attribute_add_param_with_value (attr,
+ e_vcard_attribute_param_new (EMA_X_MEMBERID),
+ str);
+ g_free (str);
+
+ /* keep the value from ListMembers with the email, to not need to generate it on list changes;
+ new values added in evolution-mapi will be always SMTP addresses anyway */
+ str = bin_to_string (members_dlist->bin[i].lpb, members_dlist->bin[i].cb);
+ if (str) {
+ e_vcard_attribute_add_param_with_value (attr,
+ e_vcard_attribute_param_new (EMA_X_MEMBERVALUE),
+ str);
+ g_free (str);
+ }
+
+ attrs = g_slist_prepend (attrs, attr);
+ }
+
+ g_free (display_name);
+ g_free (email);
}
- #define FREE(x) if (x) { g_free (x); x = NULL; }
- #define UNREF(x) if (x) { g_object_unref (x); x = NULL; }
+ for (a = attrs; a; a = a->next) {
+ e_vcard_add_attribute (E_VCARD (contact), a->data);
+ }
- /* this will also ensure any pending authentication
- request is finished and it's safe to free memory */
- g_static_mutex_lock (&priv->running_mutex);
+ g_slist_free (attrs);
- UNREF (priv->summary);
- UNREF (priv->cache);
- UNREF (priv->conn);
+ return contact;
+ }
- FREE (priv->profile);
- FREE (priv->uri);
- FREE (priv->summary_file_name);
+ for (i = 0; i < G_N_ELEMENTS (mappings); i++) {
+ gpointer value;
+ gint contact_type;
+
+ /* can cast value, no writing to the value; and it'll be freed not before the end of this function */
+ if (mappings[i].contact_type & ELEMENT_TYPE_NAMEDID)
+ value = (gpointer) get_namedid (mappings[i].mapi_id);
+ else
+ value = (gpointer) get_proptag (mappings[i].mapi_id);
+ contact_type = mappings[i].contact_type & ELEMENT_TYPE_MASK;
+ if (mappings[i].element_type == PT_UNICODE && contact_type == ELEMENT_TYPE_SIMPLE) {
+ if (value)
+ e_contact_set (contact, mappings[i].field_id, value);
+ } else if (contact_type == ELEMENT_TYPE_SIMPLE) {
+ if (value && mappings[i].element_type == PT_SYSTIME) {
+ struct FILETIME *t = value;
+ time_t time;
+ NTTIME nt;
+ gchar buff[129];
+
+ nt = t->dwHighDateTime;
+ nt = nt << 32;
+ nt |= t->dwLowDateTime;
+ time = nt_time_to_unix (nt);
+ e_contact_set (contact, mappings[i].field_id, ctime_r (&time, buff));
+ }
+ } else if (contact_type == ELEMENT_TYPE_COMPLEX) {
+ if (mappings[i].field_id == E_CONTACT_IM_AIM) {
+ GList *list = g_list_append (NULL, value);
+
+ e_contact_set (contact, mappings[i].field_id, list);
+
+ g_list_free (list);
+ } else if (mappings[i].field_id == E_CONTACT_BIRTH_DATE
+ || mappings[i].field_id == E_CONTACT_ANNIVERSARY) {
+ struct FILETIME *t = value;
+ time_t time;
+ NTTIME nt;
+ struct tm * tmtime;
+ if (value) {
+ EContactDate date = {0};
+ nt = t->dwHighDateTime;
+ nt = nt << 32;
+ nt |= t->dwLowDateTime;
+ time = nt_time_to_unix (nt);
+ tmtime = gmtime (&time);
+ //FIXME: Move to new libmapi api to get string dates.
+ date.day = tmtime->tm_mday;
+ date.month = tmtime->tm_mon + 1;
+ date.year = tmtime->tm_year + 1900;
+ e_contact_set (contact, mappings[i].field_id, &date);
+ }
- g_static_mutex_unlock (&priv->running_mutex);
- g_static_mutex_free (&priv->running_mutex);
+ } else if (mappings[i].field_id == E_CONTACT_ADDRESS_WORK
+ || mappings[i].field_id == E_CONTACT_ADDRESS_HOME) {
+ EContactAddress contact_addr = { 0 };
+
+ /* type-casting below to not allocate memory twice; e_contact_set will copy values itself. */
+ if (mappings[i].field_id == E_CONTACT_ADDRESS_HOME) {
+ contact_addr.address_format = NULL;
+ contact_addr.po = NULL;
+ contact_addr.street = (gchar *)value;
+ contact_addr.ext = (gchar *) get_str_proptag (PR_HOME_ADDRESS_POST_OFFICE_BOX_UNICODE);
+ contact_addr.locality = (gchar *) get_str_proptag (PR_HOME_ADDRESS_CITY_UNICODE);
+ contact_addr.region = (gchar *) get_str_proptag (PR_HOME_ADDRESS_STATE_OR_PROVINCE_UNICODE);
+ contact_addr.code = (gchar *) get_str_proptag (PR_HOME_ADDRESS_POSTAL_CODE_UNICODE);
+ contact_addr.country = (gchar *) get_str_proptag (PR_HOME_ADDRESS_COUNTRY_UNICODE);
+ } else {
+ contact_addr.address_format = NULL;
+ contact_addr.po = NULL;
+ contact_addr.street = (gchar *)value;
+ contact_addr.ext = (gchar *) get_str_proptag (PR_POST_OFFICE_BOX_UNICODE);
+ contact_addr.locality = (gchar *) get_str_proptag (PR_LOCALITY_UNICODE);
+ contact_addr.region = (gchar *) get_str_proptag (PR_STATE_OR_PROVINCE_UNICODE);
+ contact_addr.code = (gchar *) get_str_proptag (PR_POSTAL_CODE_UNICODE);
+ contact_addr.country = (gchar *) get_str_proptag (PR_COUNTRY_UNICODE);
+ }
+ e_contact_set (contact, mappings[i].field_id, &contact_addr);
+ }
+ }
+ }
- FREE (mapi_backend->priv);
+ if (!e_contact_get (contact, E_CONTACT_EMAIL_1)) {
+ gconstpointer value = get_proptag (PR_SMTP_ADDRESS_UNICODE);
- #undef UNREF
- #undef FREE
+ if (value)
+ e_contact_set (contact, E_CONTACT_EMAIL_1, value);
}
- /* Chain up to parent's dispose() method. */
- if (G_OBJECT_CLASS (e_book_backend_mapi_parent_class)->dispose)
- G_OBJECT_CLASS (e_book_backend_mapi_parent_class)->dispose (object);
-}
+ #undef get_proptag
+ #undef get_str_proptag
+ #undef get_namedid
+ #undef get_str_namedid
-static void e_book_backend_mapi_class_init (EBookBackendMAPIClass *klass)
-{
- GObjectClass *object_class = G_OBJECT_CLASS (klass);
- EBookBackendClass *parent_class;
-
- parent_class = E_BOOK_BACKEND_CLASS (klass);
-
- /* Set the virtual methods. */
- parent_class->load_source = e_book_backend_mapi_load_source;
- parent_class->get_static_capabilities = e_book_backend_mapi_get_static_capabilities;
- parent_class->create_contact = e_book_backend_mapi_create_contact;
- parent_class->remove_contacts = e_book_backend_mapi_remove_contacts;
- parent_class->modify_contact = e_book_backend_mapi_modify_contact;
- parent_class->get_contact = e_book_backend_mapi_get_contact;
- parent_class->get_contact_list = e_book_backend_mapi_get_contact_list;
- parent_class->start_book_view = e_book_backend_mapi_start_book_view;
- parent_class->stop_book_view = e_book_backend_mapi_stop_book_view;
- parent_class->get_changes = e_book_backend_mapi_get_changes;
- parent_class->authenticate_user = e_book_backend_mapi_authenticate_user;
- parent_class->get_required_fields = e_book_backend_mapi_get_required_fields;
- parent_class->get_supported_fields = e_book_backend_mapi_get_supported_fields;
- parent_class->get_supported_auth_methods = e_book_backend_mapi_get_supported_auth_methods;
- parent_class->cancel_operation = e_book_backend_mapi_cancel_operation;
- parent_class->remove = e_book_backend_mapi_remove;
- parent_class->set_mode = e_book_backend_mapi_set_mode;
-
- object_class->dispose = e_book_backend_mapi_dispose;
+ return contact;
}
-EBookBackend *e_book_backend_mapi_new (void)
+void
+mapi_error_to_edb_error (GError **perror, const GError *mapi_error, EDataBookStatus code, const gchar *context)
{
- EBookBackendMAPI *backend;
+ gchar *err_msg = NULL;
+
+ if (!perror)
+ return;
+
+ if (code == E_DATA_BOOK_STATUS_OTHER_ERROR && mapi_error) {
+ /* Change error to more accurate only with OTHER_ERROR */
+ switch (mapi_error->code) {
+ case MAPI_E_PASSWORD_CHANGE_REQUIRED:
+ case MAPI_E_PASSWORD_EXPIRED:
+ code = E_DATA_BOOK_STATUS_AUTHENTICATION_REQUIRED;
+ break;
+ default:
+ break;
+ }
+ }
+
+ if (context)
+ err_msg = g_strconcat (context, mapi_error ? ": " : NULL, mapi_error ? mapi_error->message : NULL, NULL);
+ else if (!mapi_error)
+ err_msg = g_strdup (_("Uknown error"));
+
+ g_propagate_error (perror, e_data_book_create_error (code, err_msg ? err_msg : mapi_error->message));
- backend = g_object_new (E_TYPE_BOOK_BACKEND_MAPI, NULL);
- return E_BOOK_BACKEND (backend);
+ g_free (err_msg);
}
diff --git a/src/addressbook/e-book-backend-mapi.h b/src/addressbook/e-book-backend-mapi.h
index 46d495d..ffba273 100644
--- a/src/addressbook/e-book-backend-mapi.h
+++ b/src/addressbook/e-book-backend-mapi.h
@@ -14,9 +14,6 @@
* License along with the program; if not, see <http://www.gnu.org/licenses/>
*
*
- * Authors:
- * Srinivasa Ragavan <sragavan novell com>
- *
* Copyright (C) 1999-2008 Novell, Inc. (www.novell.com)
*
*/
@@ -24,20 +21,27 @@
#ifndef __E_BOOK_BACKEND_MAPI_H__
#define __E_BOOK_BACKEND_MAPI_H__
+#include <glib.h>
+#include <gio/gio.h>
+
#include <libedata-book/e-book-backend.h>
-#include <libedata-book/e-book-backend-sync.h>
+#include <libedata-book/e-book-backend-cache.h>
+#include <libedata-book/e-book-backend-summary.h>
+#include <libedata-book/e-data-book.h>
+#include <libedata-book/e-data-book-view.h>
+
#include "exchange-mapi-connection.h"
#include "exchange-mapi-defs.h"
#include "exchange-mapi-utils.h"
-/* #include "db.h" */
+G_BEGIN_DECLS
-#define E_TYPE_BOOK_BACKEND_MAPI (e_book_backend_mapi_get_type ())
-#define E_BOOK_BACKEND_MAPI(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), E_TYPE_BOOK_BACKEND_MAPI, EBookBackendMAPI))
-#define E_BOOK_BACKEND_MAPI_CLASS(k) (G_TYPE_CHECK_CLASS_CAST((k), E_TYPE_BOOK_BACKEND_MAPI, EBookBackendMAPIClass))
-#define E_IS_BOOK_BACKEND_MAPI(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), E_TYPE_BOOK_BACKEND_MAPI))
-#define E_IS_BOOK_BACKEND_MAPI_CLASS(k) (G_TYPE_CHECK_CLASS_TYPE ((k), E_TYPE_BOOK_BACKEND_MAPI))
-#define E_BOOK_BACKEND_MAPI_GET_CLASS(k) (G_TYPE_INSTANCE_GET_CLASS ((obj), E_TYPE_BOOK_BACKEND_MAPI, EBookBackendMAPIClass))
+#define E_TYPE_BOOK_BACKEND_MAPI (e_book_backend_mapi_get_type ())
+#define E_BOOK_BACKEND_MAPI(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), E_TYPE_BOOK_BACKEND_MAPI, EBookBackendMAPI))
+#define E_BOOK_BACKEND_MAPI_CLASS(k) (G_TYPE_CHECK_CLASS_CAST((k), E_TYPE_BOOK_BACKEND_MAPI, EBookBackendMAPIClass))
+#define E_IS_BOOK_BACKEND_MAPI(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), E_TYPE_BOOK_BACKEND_MAPI))
+#define E_IS_BOOK_BACKEND_MAPI_CLASS(k) (G_TYPE_CHECK_CLASS_TYPE ((k), E_TYPE_BOOK_BACKEND_MAPI))
+#define E_BOOK_BACKEND_MAPI_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), E_TYPE_BOOK_BACKEND_MAPI, EBookBackendMAPIClass))
typedef struct _EBookBackendMAPIPrivate EBookBackendMAPIPrivate;
@@ -50,9 +54,78 @@ typedef struct
typedef struct
{
EBookBackendClass parent_class;
+
+ void (*op_load_source) (EBookBackendMAPI *ebma, ESource *source, gboolean only_if_exists, GError **error);
+ void (*op_remove) (EBookBackendMAPI *ebma, GError **error);
+
+ void (*op_create_contact) (EBookBackendMAPI *ebma, const gchar *vcard, EContact **contact, GError **error);
+ void (*op_remove_contacts) (EBookBackendMAPI *ebma, const GList *id_list, GList **removed_ids, GError **error);
+ void (*op_modify_contact) (EBookBackendMAPI *ebma, const gchar *vcard, EContact **contact, GError **error);
+ void (*op_get_contact) (EBookBackendMAPI *ebma, const gchar *id, gchar **vcard, GError **error);
+ void (*op_get_contact_list) (EBookBackendMAPI *ebma, const gchar *query, GList **vCards, GError **error);
+ void (*op_get_changes) (EBookBackendMAPI *ebma, const gchar *change_id, GList **changes, GError **error);
+ void (*op_authenticate_user) (EBookBackendMAPI *ebma, const gchar *user, const gchar *passwd, const gchar *auth_method, GError **error);
+ void (*op_get_required_fields) (EBookBackendMAPI *ebma, GList **fields, GError **error);
+ void (*op_get_supported_fields) (EBookBackendMAPI *ebma, GList **fields, GError **error);
+ void (*op_get_supported_auth_methods) (EBookBackendMAPI *ebma, GList **auth_methods, GError **error);
+
+ /* called when online state changes on the backend */
+ void (*op_connection_status_changed) (EBookBackendMAPI *ebma, gboolean is_online);
+
+ /* returns a status message for a progress of fetching entries "index/total";
+ returned string is freed by g_free() */
+ gchar * (*op_get_status_message) (EBookBackendMAPI *ebma, gint index, gint total);
+
+ /* function called for each new book_view, in a separate thread;
+ this function is optional, contacts from cache are always processed
+ before this function call */
+ void (*op_book_view_thread) (EBookBackendMAPI *ebma, EDataBookView *book_view, GError **error);
+
+ /* function called to populate cache or similar operations;
+ restriction and book_view can be NULL, call e_book_backend_mapi_notify_contact_update for each
+ fetched contact with this book_view and notify_contact_data */
+ void (*op_fetch_contacts) (EBookBackendMAPI *ebma, struct mapi_SRestriction *restriction, EDataBookView *book_view, gpointer notify_contact_data, GError **error);
+
+ /* function to fetch list of known uids (strings) on the server;
+ it's used to synchronize local cache with deleted items;
+ uids has the uid key, as a newly allocated string; value should be GINT_TO_POINTER(1) always */
+ void (*op_fetch_known_uids) (EBookBackendMAPI *ebma, GCancellable *cancelled, GHashTable *uids, GError **error);
} EBookBackendMAPIClass;
-EBookBackend *e_book_backend_mapi_new (void);
-GType e_book_backend_mapi_get_type (void);
+GType e_book_backend_mapi_get_type (void);
+
+gboolean e_book_backend_mapi_debug_enabled (void);
+const gchar *e_book_backend_mapi_get_book_uri (EBookBackendMAPI *ebma);
+void e_book_backend_mapi_lock_connection (EBookBackendMAPI *ebma);
+void e_book_backend_mapi_unlock_connection (EBookBackendMAPI *ebma);
+ExchangeMapiConnection *e_book_backend_mapi_get_connection (EBookBackendMAPI *ebma);
+void e_book_backend_mapi_get_summary_and_cache (EBookBackendMAPI *ebma, EBookBackendSummary **summary, EBookBackendCache **cache);
+gboolean e_book_backend_mapi_book_view_is_running (EBookBackendMAPI *ebma, EDataBookView *book_view);
+void e_book_backend_mapi_update_view_by_cache (EBookBackendMAPI *ebma, EDataBookView *book_view, GError **error);
+gboolean e_book_backend_mapi_is_marked_for_offline (EBookBackendMAPI *ebma);
+gboolean e_book_backend_mapi_notify_contact_update (EBookBackendMAPI *ebma, EDataBookView *book_view, EContact *contact, const struct timeval *pr_last_modification_time, gint index, gint total, gpointer notify_contact_data);
+void e_book_backend_mapi_notify_contact_removed (EBookBackendMAPI *ebma, const gchar *uid);
+
+/* utility functions/macros */
+
+#define EDB_ERROR(_code) e_data_book_create_error (E_DATA_BOOK_STATUS_ ## _code, NULL)
+#define EDB_ERROR_EX(_code, _msg) e_data_book_create_error (E_DATA_BOOK_STATUS_ ## _code, _msg)
+
+void mapi_error_to_edb_error (GError **perror, const GError *mapi_error, EDataBookStatus code, const gchar *context);
+
+/* vCard parameter name in contact list */
+#define EMA_X_MEMBERID "X-EMA-MEMBER-ID"
+#define EMA_X_MEMBERVALUE "X-EMA-MEMBER-VALUE"
+
+#define GET_ALL_KNOWN_IDS (GINT_TO_POINTER(1))
+#define GET_UIDS_ONLY (GINT_TO_POINTER(2))
+
+/* data is one of GET_ALL_KNOWN_IDS or GET_UIDS_ONLY */
+gboolean mapi_book_utils_get_prop_list (ExchangeMapiConnection *conn, mapi_id_t fid, TALLOC_CTX *mem_ctx, struct SPropTagArray *props, gpointer data);
+
+/* only one of mapi_properties and aRow can be set */
+EContact *mapi_book_utils_contact_from_props (ExchangeMapiConnection *conn, mapi_id_t fid, const gchar *book_uri, struct mapi_SPropValue_array *mapi_properties, struct SRow *aRow);
+
+G_END_DECLS
#endif /* __E_BOOK_BACKEND_MAPI_H__ */
diff --git a/src/libexchangemapi/exchange-mapi-connection.c b/src/libexchangemapi/exchange-mapi-connection.c
index ffb11c5..4329bd9 100644
--- a/src/libexchangemapi/exchange-mapi-connection.c
+++ b/src/libexchangemapi/exchange-mapi-connection.c
@@ -1119,7 +1119,7 @@ cleanup:
}
gboolean
-exchange_mapi_connection_fetch_gal (ExchangeMapiConnection *conn, BuildReadPropsCB build_props, gpointer brp_data, FetchGALCallback cb, gpointer data, GError **perror)
+exchange_mapi_connection_fetch_gal (ExchangeMapiConnection *conn, struct mapi_SRestriction *restrictions, BuildReadPropsCB build_props, gpointer brp_data, FetchGALCallback cb, gpointer data, GError **perror)
{
struct SPropTagArray *propsTagArray;
struct SRowSet *aRowSet;
@@ -1157,8 +1157,8 @@ exchange_mapi_connection_fetch_gal (ExchangeMapiConnection *conn, BuildReadProps
ulFlags = TABLE_START;
while (ms == MAPI_E_SUCCESS) {
aRowSet = NULL;
- /* fetch per 10 items */
- ms = GetGALTable (priv->session, propsTagArray, &aRowSet, 10, ulFlags);
+ /* fetch per 100 items */
+ ms = GetGALTable (priv->session, propsTagArray, &aRowSet, 100, ulFlags);
if ((!aRowSet) || (!(aRowSet->aRow)) || ms != MAPI_E_SUCCESS) {
break;
}
diff --git a/src/libexchangemapi/exchange-mapi-connection.h b/src/libexchangemapi/exchange-mapi-connection.h
index c7fe895..491bba2 100644
--- a/src/libexchangemapi/exchange-mapi-connection.h
+++ b/src/libexchangemapi/exchange-mapi-connection.h
@@ -175,7 +175,7 @@ gboolean exchange_mapi_connection_fetch_items (ExchangeMapiConnection *conn, ma
FetchCallback cb, gpointer data,
guint32 options, GError **perror);
-gboolean exchange_mapi_connection_fetch_gal (ExchangeMapiConnection *conn,
+gboolean exchange_mapi_connection_fetch_gal (ExchangeMapiConnection *conn, struct mapi_SRestriction *restrictions,
BuildReadPropsCB build_props, gpointer brp_data,
FetchGALCallback cb, gpointer data, GError **perror);
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]