implement Contacts API using Evolution Data Server (TIVI-1407) 85/12585/2 accepted/tizen/20131126.000807 accepted/tizen/20131203.012844 accepted/tizen/20131203.013843 accepted/tizen/20131206.003808 accepted/tizen/generic/20140123.231542 accepted/tizen/ivi/20140123.224552 accepted/tizen/ivi/release/20140123.230659 submit/tizen/20131125.205736 submit/tizen/20131203.004233 submit/tizen/20131203.004346 submit/tizen/20131203.013028 submit/tizen/20131203.014052 submit/tizen/20140123.225036 submit/tizen_ivi_release/20140123.225938 submit/tizen_ivi_release/20140123.230656 submit/tizen_ivi_release/20140123.231141
authorPatrick Ohly <patrick.ohly@intel.com>
Tue, 12 Nov 2013 15:56:48 +0000 (16:56 +0100)
committerRusty Lynch <rusty.lynch@intel.com>
Tue, 19 Nov 2013 19:01:47 +0000 (11:01 -0800)
The implementation was done with a combination of ifdefs and contacts
service API emulation. The default is to build the plugin for contacts
service.

An EDS with the new Cursor API is needed.

See src/Contact/contacts2ebook/README for more information about
design choices, usage and limitations.

Change-Id: Id9932a18202f90697958c39c9a7c1062b8f07c4e
Signed-off-by: Patrick Ohly <patrick.ohly@intel.com>
27 files changed:
CMakeLists.txt
packaging/wrt-plugins-tizen.changes
packaging/wrt-plugins-tizen.spec
src/Contact/AddressBook.cpp
src/Contact/AddressBook.h
src/Contact/CMakeLists.txt
src/Contact/Contact.cpp
src/Contact/ContactManager.cpp
src/Contact/ContactObjectA2PConverter.cpp
src/Contact/ContactObjectA2PConverter.h
src/Contact/ContactObjectP2AConverter.cpp
src/Contact/ContactObjectP2AConverter.h
src/Contact/ContactSearchEngine.cpp
src/Contact/ContactSearchEngine.h
src/Contact/ContactsSvcChangeListenerManager.cpp
src/Contact/ContactsSvcChangeListenerManager.h
src/Contact/ContactsSvcObjectConverter.cpp
src/Contact/ContactsSvcWrapper.cpp
src/Contact/ContactsSvcWrapper.h
src/Contact/IAddressBook.h
src/Contact/JSAddressBook.cpp
src/Contact/Person.cpp
src/Contact/PersonSearchEngine.cpp
src/Contact/PersonSearchEngine.h
src/Contact/contacts2ebook/GLibSupport.h [new file with mode: 0644]
src/Contact/contacts2ebook/README [new file with mode: 0644]
src/Contact/contacts2ebook/contacts.h [new file with mode: 0644]

index 80baa2d..5afd1bf 100755 (executable)
@@ -98,6 +98,12 @@ IF(ENABLE_OPTIONAL_MSG_PORT)
     ADD_DEFINITIONS( -DFEATURE_OPTIONAL_MSG_PORT )
 ENDIF(ENABLE_OPTIONAL_MSG_PORT)
 
+IF(WITH_EBOOK)
+    # Replaces the default contacts-service2.
+    MESSAGE(STATUS "Contacts API using Evolution Data Server libebook")
+    ADD_DEFINITIONS( -DFEATURE_EBOOK )
+ENDIF(WITH_EBOOK)
+
 IF(ENABLE_OPTIONAL_SYSINFO_TEL_SIM_MNGT)
     MESSAGE(STATUS "System-info SIM management API Enabled")
     ADD_DEFINITIONS( -DENABLE_OPTIONAL_SYSINFO_TEL_SIM_MNGT )
index 7d0754c..fa3c13d 100644 (file)
@@ -1,3 +1,6 @@
+* Tue Nov 19 2013 Patrick Ohly <patrick.ohly@intel.com> accepted/tizen/20131118.182136@e0defdb
+- implement Contacts API using Evolution Data Server (TIVI-1407)
+
 * Tue Nov 19 2013 Rusty Lynch <rusty.lynch@intel.com> accepted/tizen/20131118.182136@7cc7b09
 - message-port: Add explicit check for capi-appfw-app-manager
 - Fix  TIVI-2057 : Set request mode for installation / uninstallation to quiet mode.
index 5392c5e..6149055 100755 (executable)
@@ -7,6 +7,7 @@
 %bcond_with wrt_option_sysinfo_tel_sim_mngt
 %bcond_with wrt_option_sysinfo_cellular_network_mngt
 %bcond_with wrt_option_msg_port
+%bcond_with wrt_option_eds
 Name:       wrt-plugins-tizen
 Summary:    JavaScript plugins for WebRuntime
 Version:    0.4.68
@@ -18,7 +19,14 @@ BuildRequires:  pkgconfig(capi-web-favorites)
 BuildRequires:  pkgconfig(mm-fileinfo)
 BuildRequires:  pkgconfig(libpcrecpp)
 BuildRequires:  pkgconfig(calendar-service2)
+%if %{with wrt_option_eds}
+BuildRequires:  pkgconfig(libebook-1.2)
+%else
 BuildRequires:  pkgconfig(contacts-service2)
+%endif
+%if %{with wrt_option_call_history}
+BuildRequires:  pkgconfig(contacts-service2)
+%endif
 BuildRequires:  pkgconfig(msg-service)
 BuildRequires:  pkgconfig(email-service)
 BuildRequires:  pkgconfig(accounts-svc)
@@ -147,6 +155,9 @@ export FFLAGS="$FFLAGS -DTIZEN_ENGINEER_MODE"
 %if %{with wrt_option_msg_port}
     -DENABLE_OPTIONAL_MSG_PORT=YES \
 %endif
+%if %{with wrt_option_eds}
+   -DWITH_EBOOK=YES \
+%endif
 . -DCMAKE_INSTALL_PREFIX=%{_prefix} -DDPL_LOG="ON" -DENABLE_TIME_TRACER="OFF"
 
 make %{?jobs:-j%jobs}
index b447703..ffa3e1f 100755 (executable)
@@ -49,38 +49,96 @@ using namespace DeviceAPI::Tizen;
 using namespace WrtDeviceApis::Commons;
 using namespace std;
 
-AddressBook::AddressBook(bool isUnified) :
+AddressBook::AddressBook(
+#ifdef FEATURE_EBOOK
+                        EBookClientCXX &ebook
+#else
+                        bool isUnified
+#endif
+                        ) :
                IAddressBook(),
+#ifdef FEATURE_EBOOK
+               m_ebook(ebook),
+#else
                m_id(0),
+#endif
                m_name("TEST_ADDRESS_BOOK"),
                m_readOnly(false),
                m_accountId(0),
-               m_isUnifiedAddressBook(isUnified),
+               m_isUnifiedAddressBook(
+#ifdef FEATURE_EBOOK
+                                      false
+#else
+                                      isUnified
+#endif
+                                      ),
                m_eventMapAcc(100)
 {
     LoggerD("entered");
+#ifdef FEATURE_EBOOK
+    // Initialize view. It will be activated only if the JS side asks
+    // to watch for changes.
+    EBookQueryCXX allItemsQuery(e_book_query_any_field_contains(""), TRANSFER_REF);
+    PlainGStr sexp(e_book_query_to_string (allItemsQuery.get()));
+    EBookClientView *view;
+    GErrorCXX gerror;
+    if (!e_book_client_get_view_sync(m_ebook, sexp, &view, NULL, gerror))
+           ThrowMsg(PlatformException, gerror.msg());
+    m_view.take(view);
+    m_view.connectSignal<void (EBookClientView *ebookview,
+                              GSList *data)>("objects-added", boost::bind(&AddressBook::onContactsEDSContactsAddedOrUpdated,
+                                                                           this,
+                                                                           _2,
+                                                                           &AddressBook::onContactsSvcContactsAdded));
+    m_view.connectSignal<void (EBookClientView *ebookview,
+                              GSList *data)>("objects-modified", boost::bind(&AddressBook::onContactsEDSContactsAddedOrUpdated,
+                                                                             this,
+                                                                             _2,
+                                                                             &AddressBook::onContactsSvcContactsUpdated));
+    m_view.connectSignal<void (EBookClientView *ebookview,
+                              GSList *data)>("objects-removed", boost::bind(&AddressBook::onContactsEDSContactsRemoved,
+                                                                            this,
+                                                                            _2));
+    e_book_client_view_set_flags(m_view, E_BOOK_CLIENT_VIEW_FLAGS_NONE, gerror);
+    if (gerror)
+           ThrowMsg(PlatformException, gerror.msg());
+#endif
 }
 
 AddressBook::~AddressBook()
 {
+#ifndef FEATURE_EBOOK
        if(m_addressBookEmitters.size() != 0)
        {
                ContactsSvcChangeListenerManagerSingleton::Instance().unregisterContactsChangeListener(this);
        }
+#endif
 }
 
 std::string AddressBook::getId() const
 {
+#ifdef FEATURE_EBOOK
+       ESource *esource = e_client_get_source(E_CLIENT(m_ebook.get()));
+       const char *uid = e_source_get_uid(esource);
+       // Use "0" instead of real "system-address-book" UID for the
+       // default system address book, for compatibility with apps
+       // which (incorrectly) have that id hard-coded.
+       const char *id = strcmp(uid, "system-address-book") ? uid : "0";
+       return id;
+#else
        if(m_isUnifiedAddressBook)
                return string("");
 
        return ContactUtility::intToStr(m_id);
+#endif
 }
 
+#ifndef FEATURE_EBOOK
 void AddressBook::setId(const std::string &value)
 {
        m_id = ContactUtility::strToInt(value);
 }
+#endif
 
 std::string AddressBook::getAccountId() const
 {
@@ -99,7 +157,6 @@ void AddressBook::OnRequestReceived(const EventAddressBookGetPtr &event)
 {
        LoggerD("entered");
 
-       int errorCode = 0;
        contacts_record_h contacts_record = NULL;
 
        Try
@@ -109,6 +166,15 @@ void AddressBook::OnRequestReceived(const EventAddressBookGetPtr &event)
 
                string contactId = event->getId();
 
+#ifdef FEATURE_EBOOK
+               EContact *econtact;
+               GErrorCXX gerror;
+               if (!e_book_client_get_contact_sync(m_ebook, contactId.c_str(), &econtact, NULL, gerror)) {
+                       ThrowMsg(NotFoundException, gerror.msg());
+               }
+               contacts_record.take(econtact);
+#else
+               int errorCode = 0;
                int contactIdInt = ContactUtility::strToInt(contactId);
 
                errorCode = contacts_db_get_record(_contacts_contact._uri, contactIdInt, &contacts_record);
@@ -122,9 +188,14 @@ void AddressBook::OnRequestReceived(const EventAddressBookGetPtr &event)
                        if(addressBookId != m_id)
                                ThrowMsg(NotFoundException, "No contact in this address book.");
                }
+#endif
 
                ContactObjectP2AConverterPtr contactObjConverter(
-                               new ContactObjectP2AConverter(contacts_record, false));
+                               new ContactObjectP2AConverter(contacts_record,
+#ifdef FEATURE_EBOOK
+                                                             m_ebook,
+#endif
+                                                             false));
                ContactPtr contact = contactObjConverter->getAbstractContact();
 
                event->setContact(contact);
@@ -155,7 +226,7 @@ void AddressBook::OnRequestReceived(const EventAddressBookGetPtr &event)
                event->setResult(false);
        }
 
-       if(contacts_record != NULL)
+       if(contacts_record)
                contacts_record_destroy(contacts_record, true);
 }
 
@@ -198,36 +269,60 @@ void AddressBook::OnRequestReceived(const EventAddressBookAddPtr &event)
                ContactObjectA2PConverterPtr contactObjConverter(NULL);
 
                contacts_record = contactT->getPlatformContactObject();
-               if(contacts_record == NULL)
+               if(!contacts_record)
                {
                        contactObjConverter = ContactObjectA2PConverterPtr(
-                                       new ContactObjectA2PConverter(contact, false) );
+                                       new ContactObjectA2PConverter(contact,
+#ifdef FEATURE_EBOOK
+                                                                     m_ebook,
+#endif
+                                                                     false) );
                        contacts_record = contactObjConverter->getPlatformContact();
                }
                else
                {
                        contactObjConverter = ContactObjectA2PConverterPtr(
-                                       new ContactObjectA2PConverter(contact, false, contacts_record) );
+                                       new ContactObjectA2PConverter(contact,
+#ifdef FEATURE_EBOOK
+                                                                     m_ebook,
+#endif
+                                                                     false, contacts_record) );
                        contacts_record = contactObjConverter->getPlatformContact();
                }
 
-               int contactId = 0;
                if (!contacts_record)
                {
                        LoggerE("Error during converting contact object");
                        ThrowMsg(PlatformException, "Error during converting contact object");
                }
 
+#ifndef FEATURE_EBOOK
                if(m_isUnifiedAddressBook)
                        errorCode = contacts_record_set_int(contacts_record, _contacts_contact.address_book_id, 0);
                else
                        errorCode = contacts_record_set_int(contacts_record, _contacts_contact.address_book_id, m_id);
+#endif
+
                if(errorCode != CONTACTS_ERROR_NONE)
                {
                        LoggerE("error code : " << errorCode);
                        ThrowMsg(PlatformException, "Error during executing contacts_db_insert_record()");
                }
 
+#ifdef FEATURE_EBOOK
+               char *uid;
+               GErrorCXX gerror;
+               if (!e_book_client_add_contact_sync(m_ebook, contacts_record, &uid, NULL, gerror)) {
+                       ThrowMsg(PlatformException, gerror.msg());
+               }
+               e_contact_set(contacts_record, E_CONTACT_UID, uid);
+               g_free(uid);
+               // TODO? Retrieve REV and store in m_platformContact.
+
+               // Must have been saved exactly as requested, so no need to read from DB.
+               get_contacts_record = contacts_record;
+#else
+               int contactId = 0;
                errorCode = contacts_db_insert_record(contacts_record, &contactId);
                if(errorCode != CONTACTS_ERROR_NONE)
                {
@@ -238,9 +333,14 @@ void AddressBook::OnRequestReceived(const EventAddressBookAddPtr &event)
                errorCode = contacts_db_get_record(_contacts_contact._uri, contactId, &get_contacts_record);
                if(errorCode != CONTACTS_ERROR_NONE || get_contacts_record == NULL)
                        ThrowMsg(PlatformException, "No contact just inserted");
+#endif
 
                ContactObjectP2AConverterPtr contactObjConverterForInserted(
-                               new ContactObjectP2AConverter(get_contacts_record, false));
+                               new ContactObjectP2AConverter(get_contacts_record,
+#ifdef FEATURE_EBOOK
+                                                             m_ebook,
+#endif
+                                                             false));
                ContactPtr insertedContact = contactObjConverterForInserted->getAbstractContact();
 
                contact->copy(insertedContact);
@@ -260,7 +360,7 @@ void AddressBook::OnRequestReceived(const EventAddressBookAddPtr &event)
                event->setExceptionCode(ExceptionCodes::UnknownException);
        }
 
-       if(get_contacts_record != NULL)
+       if(get_contacts_record)
                contacts_record_destroy(get_contacts_record, true);
 }
 
@@ -269,7 +369,7 @@ void AddressBook::AddressBookAddBatch(const EventAddressBookAddBatchPtr &event)
        LoggerD("entered");
 
        int errorCode = 0;
-       contacts_list_h contacts_list = NULL;
+       contacts_list_h contacts_list(NULL);
        ContactArrayPtr contacts(NULL);
 
        if(!event->getContactsIsSet())
@@ -296,28 +396,42 @@ void AddressBook::AddressBookAddBatch(const EventAddressBookAddBatchPtr &event)
                        DPL::SharedPtr<Contact> newContactT =
                                        DPL::StaticPointerCast<Contact>(contact);
                        contacts_record = newContactT->getPlatformContactObject();
-                       if(contacts_record == NULL)
+                       if(!contacts_record)
                        {
+#ifdef FEATURE_EBOOK
+                               contacts_record.take(e_contact_new());
+                               if(!contacts_record)
+                               {
+                                       ThrowMsg(PlatformException, "Error during creating contact record");
+                               }
+#else
                                errorCode = contacts_record_create(_contacts_contact._uri, &contacts_record);
                                if(errorCode != CONTACTS_ERROR_NONE)
                                {
                                        ThrowMsg(PlatformException, "Error during creating contact record : " << errorCode);
                                }
+#endif
                        }
 
                        contactObjConverter = ContactObjectA2PConverterPtr(
-                                       new ContactObjectA2PConverter(contact, false, contacts_record) );
+                                       new ContactObjectA2PConverter(contact,
+#ifdef FEATURE_EBOOK
+                                                                     m_ebook,
+#endif
+                                                                     false, contacts_record) );
                        contacts_record = contactObjConverter->getPlatformContact();
 
-                       if(contacts_record == NULL)
+                       if(!contacts_record)
                        {
                                ThrowMsg(PlatformException, "Error during converting contact object");
                        }
 
+#ifndef FEATURE_EBOOK
                        if(m_isUnifiedAddressBook)
                                errorCode = contacts_record_set_int(contacts_record, _contacts_contact.address_book_id, 0);
                        else
                                errorCode = contacts_record_set_int(contacts_record, _contacts_contact.address_book_id, m_id);
+#endif
                        if(errorCode != CONTACTS_ERROR_NONE)
                        {
                                ThrowMsg(PlatformException, "Error during add address book : " << errorCode);
@@ -331,7 +445,7 @@ void AddressBook::AddressBookAddBatch(const EventAddressBookAddBatchPtr &event)
                }
                Catch(InvalidArgumentException)
                {
-                       if(contacts_list != NULL)
+                       if(contacts_list)
                                contacts_list_destroy(contacts_list, true);
 
                        ThrowMsg(InvalidArgumentException, "Error during converting contact object");
@@ -340,7 +454,7 @@ void AddressBook::AddressBookAddBatch(const EventAddressBookAddBatchPtr &event)
                }
                Catch(PlatformException)
                {
-                       if(contacts_list != NULL)
+                       if(contacts_list)
                                contacts_list_destroy(contacts_list, true);
 
                        ThrowMsg(PlatformException, "Error during converting contact object");
@@ -349,7 +463,7 @@ void AddressBook::AddressBookAddBatch(const EventAddressBookAddBatchPtr &event)
                }
                Catch(Exception)
                {
-                       if(contacts_list != NULL)
+                       if(contacts_list)
                                contacts_list_destroy(contacts_list, true);
 
                        ThrowMsg(Exception, "Error during converting contact object");
@@ -361,23 +475,34 @@ void AddressBook::AddressBookAddBatch(const EventAddressBookAddBatchPtr &event)
        KeySharePtrPair *keyPair = new KeySharePtrPair();
        keyPair->key = m_eventMapAcc;
        keyPair->addressBook = this;
+#ifdef FEATURE_EBOOK
+       errorCode = CONTACTS_ERROR_NONE;
+       if (contacts_list) {
+               e_book_client_add_contacts(m_ebook, contacts_list, NULL, contactsAddBatchResultCallback, keyPair);
+       } else {
+               // Don't rely on EDS handling empty lists, it doesn't
+               // invoke the callback in that case. Instead use an
+               // idle callback.  We must not invoke the callback
+               // directly here, the event is not set up for it yet
+               // (see switchToManualAnswer()).
+               g_idle_add(contactsAddBatchIdleCallback, keyPair);
+       }
+#else
        errorCode = contacts_db_insert_records_async(contacts_list, contactsAddBatchResultCallback, (void*)keyPair);
+#endif
        if(errorCode != CONTACTS_ERROR_NONE)
        {
                delete keyPair;
-               if(contacts_list != NULL)
+               if(contacts_list)
                        contacts_list_destroy(contacts_list, true);
 
                ThrowMsg(PlatformException, "Error during contacts_db_insert_records_async");
        }
 
        errorCode = contacts_list_destroy(contacts_list, true);
-       contacts_list = NULL;
        if(errorCode != CONTACTS_ERROR_NONE)
        {
                delete keyPair;
-               if(contacts_list != NULL)
-                       contacts_list_destroy(contacts_list, true);
 
                ThrowMsg(PlatformException, "Error during contacts_list_destroy");
        }
@@ -460,24 +585,30 @@ void AddressBook::OnRequestReceived(const EventAddressBookUpdatePtr &event)
 
        Try
        {
-               int errorCode = 0;
-
                DPL::SharedPtr<Contact> contactT =
                                DPL::StaticPointerCast<Contact>(contact);
 
                ContactObjectA2PConverterPtr contactObjConverter(NULL);
 
                contacts_record_h contacts_record = contactT->getPlatformContactObject();
-               if(contacts_record == NULL)
+               if(!contacts_record)
                {
                        contactObjConverter = ContactObjectA2PConverterPtr(
-                                       new ContactObjectA2PConverter(contact, false) );
+                                       new ContactObjectA2PConverter(contact,
+#ifdef FEATURE_EBOOK
+                                                                     m_ebook,
+#endif
+                                                                     false) );
                        contacts_record = contactObjConverter->getPlatformContact();
                }
                else
                {
                        contactObjConverter = ContactObjectA2PConverterPtr(
-                                       new ContactObjectA2PConverter(contact, false, contacts_record) );
+                                       new ContactObjectA2PConverter(contact,
+#ifdef FEATURE_EBOOK
+                                                                     m_ebook,
+#endif
+                                                                     false, contacts_record) );
                        contacts_record = contactObjConverter->getPlatformContact();
                }
 
@@ -487,7 +618,18 @@ void AddressBook::OnRequestReceived(const EventAddressBookUpdatePtr &event)
                        ThrowMsg(PlatformException, "Error during converting contact object");
                }
 
-               errorCode = contacts_db_update_record(contacts_record);
+#ifdef FEATURE_EBOOK
+               GErrorCXX gerror;
+               if (!e_book_client_modify_contact_sync(m_ebook, contacts_record, NULL, gerror))
+               {
+                       if (gerror.matches(E_BOOK_CLIENT_ERROR,
+                                          E_BOOK_CLIENT_ERROR_CONTACT_NOT_FOUND))
+                               ThrowMsg(NotFoundException, gerror.msg());
+                       else
+                               ThrowMsg(PlatformException, gerror.msg());
+               }
+#else
+               int errorCode = contacts_db_update_record(contacts_record);
                if (errorCode == CONTACTS_ERROR_INVALID_PARAMETER)
                        ThrowMsg(NotFoundException, "Error during executing contacts_db_update_record()");
                else if (errorCode == CONTACTS_ERROR_NO_DATA)
@@ -497,6 +639,7 @@ void AddressBook::OnRequestReceived(const EventAddressBookUpdatePtr &event)
                        LoggerE("error code : " << errorCode);
                        ThrowMsg(PlatformException, "Error during executing contacts_db_update_record()");
                }
+#endif
        }
        Catch (NotFoundException)
        {
@@ -526,7 +669,7 @@ void AddressBook::AddressBookUpdateBatch(const EventAddressBookUpdateBatchPtr &e
 {
        LoggerD("entered");
        int errorCode = 0;
-       contacts_list_h contacts_list = NULL;
+       contacts_list_h contacts_list(NULL);
        ContactArrayPtr contacts(NULL);
 
        if(!event->getContactsIsSet())
@@ -539,7 +682,7 @@ void AddressBook::AddressBookUpdateBatch(const EventAddressBookUpdateBatchPtr &e
        errorCode = contacts_list_create(&contacts_list);
        if(errorCode != CONTACTS_ERROR_NONE)
        {
-               if(contacts_list != NULL)
+               if(contacts_list)
                        contacts_list_destroy(contacts_list, false);
 
                ThrowMsg(PlatformException, "Fail to create contacts_list_h");
@@ -564,18 +707,30 @@ void AddressBook::AddressBookUpdateBatch(const EventAddressBookUpdateBatchPtr &e
 
                        DPL::SharedPtr<Contact> newContactT = DPL::StaticPointerCast<Contact>(contact);
                        contacts_record = newContactT->getPlatformContactObject();
-                       if(contacts_record == NULL)
+                       if(!contacts_record)
                        {
+#ifdef FEATURE_EBOOK
+                               EContact *econtact;
+                               GErrorCXX gerror;
+                               if (!e_book_client_get_contact_sync(m_ebook, contact->getId().c_str(), &econtact, NULL, gerror))
+                                       ThrowMsg(NotFoundException, "No contact");
+                               contacts_record.take(econtact);
+#else
                                int contactIdInt = ContactUtility::strToInt(contact->getId());
                                errorCode = contacts_db_get_record(_contacts_contact._uri, contactIdInt, &contacts_record);
                                if(errorCode != CONTACTS_ERROR_NONE || contacts_record == NULL)
                                        ThrowMsg(NotFoundException, "No contact");
+#endif
                        }
                        contactObjConverter = ContactObjectA2PConverterPtr(
-                                       new ContactObjectA2PConverter(contact, false, contacts_record) );
+                                       new ContactObjectA2PConverter(contact,
+#ifdef FEATURE_EBOOK
+                                                                     m_ebook,
+#endif
+                                                                     false, contacts_record) );
                        contacts_record = contactObjConverter->getPlatformContact();
 
-                       if(contacts_record == NULL)
+                       if(!contacts_record)
                                ThrowMsg(PlatformException, "Error during converting contact object");
 
                        errorCode = contacts_list_add(contacts_list, contacts_record);
@@ -584,7 +739,7 @@ void AddressBook::AddressBookUpdateBatch(const EventAddressBookUpdateBatchPtr &e
                }
                Catch(NotFoundException)
                {
-                       if(contacts_list != NULL)
+                       if(contacts_list)
                                contacts_list_destroy(contacts_list, false);
 
                        ThrowMsg(NotFoundException, "Error during converting contact object");
@@ -593,7 +748,7 @@ void AddressBook::AddressBookUpdateBatch(const EventAddressBookUpdateBatchPtr &e
                }
                Catch(InvalidArgumentException)
                {
-                       if(contacts_list != NULL)
+                       if(contacts_list)
                                contacts_list_destroy(contacts_list, false);
 
                        ThrowMsg(InvalidArgumentException, "Error during converting contact object");
@@ -602,7 +757,7 @@ void AddressBook::AddressBookUpdateBatch(const EventAddressBookUpdateBatchPtr &e
                }
                Catch(PlatformException)
                {
-                       if(contacts_list != NULL)
+                       if(contacts_list)
                                contacts_list_destroy(contacts_list, false);
 
                        ThrowMsg(PlatformException, "Error during converting contact object");
@@ -611,7 +766,7 @@ void AddressBook::AddressBookUpdateBatch(const EventAddressBookUpdateBatchPtr &e
                }
                Catch(Exception)
                {
-                       if(contacts_list != NULL)
+                       if(contacts_list)
                                contacts_list_destroy(contacts_list, false);
 
                        ThrowMsg(Exception, "Error during converting contact object");
@@ -623,23 +778,31 @@ void AddressBook::AddressBookUpdateBatch(const EventAddressBookUpdateBatchPtr &e
        KeySharePtrPair *keyPair = new KeySharePtrPair();
        keyPair->key = m_eventMapAcc;
        keyPair->addressBook = this;
+
+#ifdef FEATURE_EBOOK
+       errorCode = CONTACTS_ERROR_NONE;
+       if (contacts_list) {
+               e_book_client_modify_contacts(m_ebook, contacts_list, NULL, contactsUpdateBatchResultCallback, keyPair);
+       } else {
+               // See AddBatch...
+               g_idle_add(contactsUpdateBatchIdleCallback, keyPair);
+       }
+#else
        errorCode = contacts_db_update_records_async(contacts_list, contactsUpdateBatchResultCallback, (void*)keyPair);
+#endif
        if(errorCode != CONTACTS_ERROR_NONE)
        {
                delete keyPair;
-               if(contacts_list != NULL)
+               if(contacts_list)
                        contacts_list_destroy(contacts_list, false);
 
                ThrowMsg(PlatformException, "Error during contacts_db_update_records_async");
        }
 
        errorCode = contacts_list_destroy(contacts_list, true);
-       contacts_list = NULL;
        if(errorCode != CONTACTS_ERROR_NONE)
        {
                delete keyPair;
-               if(contacts_list != NULL)
-                       contacts_list_destroy(contacts_list, false);
 
                ThrowMsg(PlatformException, "Error during contacts_list_destroy");
        }
@@ -695,7 +858,6 @@ void AddressBook::OnRequestReceived(const EventAddressBookRemovePtr &event)
 {
        LoggerD("entered");
 
-       int errorCode = 0;
        Try
        {
                if(!event->getContactIdIsSet())
@@ -703,6 +865,18 @@ void AddressBook::OnRequestReceived(const EventAddressBookRemovePtr &event)
 
                string contactIdStr = event->getContactId();
 
+#ifdef FEATURE_EBOOK
+               GErrorCXX gerror;
+               if (!e_book_client_remove_contact_by_uid_sync(m_ebook, contactIdStr.c_str(), NULL, gerror)) {
+                       if (gerror.matches(E_BOOK_CLIENT_ERROR,
+                                          E_BOOK_CLIENT_ERROR_CONTACT_NOT_FOUND))
+                               ThrowMsg(NotFoundException, gerror.msg());
+                       else
+                               ThrowMsg(PlatformException, gerror.msg());
+               }
+#else
+               int errorCode = 0;
+
                if(!ContactUtility::checkStrIsUInt(contactIdStr))
                        ThrowMsg(InvalidArgumentException, "Id is wrong" );
 
@@ -735,6 +909,7 @@ void AddressBook::OnRequestReceived(const EventAddressBookRemovePtr &event)
                        ThrowMsg(NotFoundException, "Error during executing contacts_db_delete_record()");
                else if (errorCode != CONTACTS_ERROR_NONE)
                        ThrowMsg(PlatformException, "Error during executing contacts_db_delete_record()");
+#endif
        }
        Catch (InvalidArgumentException)
        {
@@ -782,9 +957,13 @@ void AddressBook::AddressBookRemoveBatch(const EventAddressBookRemoveBatchPtr &e
        if(!contactIds)
                ThrowMsg(InvalidArgumentException, "Invalid contacts");
 
+#ifdef FEATURE_EBOOK
+       UIDList ids;
+#else
        int *ids = new int[contactIds->size()];
 //             int *tmpIds = new int[contactIds->size()];
        int count = 0;
+#endif
 
        if(errorCode != CONTACTS_ERROR_NONE)
        {
@@ -797,6 +976,9 @@ void AddressBook::AddressBookRemoveBatch(const EventAddressBookRemoveBatchPtr &e
 
                Try
                {
+#ifdef FEATURE_EBOOK
+                       ids.push_front(g_strdup(contactIdStr.c_str()));
+#else
                        int contactId;
 
                        if(!ContactUtility::checkStrIsUInt(contactIdStr))
@@ -823,6 +1005,7 @@ void AddressBook::AddressBookRemoveBatch(const EventAddressBookRemoveBatchPtr &e
                        ids[count] = contactId;
 //                             tmpIds[count] = contactId;
                        count++;
+#endif
                }
                Catch(Exception)
                {
@@ -863,9 +1046,9 @@ void AddressBook::AddressBookRemoveBatch(const EventAddressBookRemoveBatchPtr &e
        if(errorCode != CONTACTS_ERROR_NONE)
                ThrowMsg(PlatformException, "contacts_db_get_count_with_query error : " << errorCode << " (" << __FUNCTION__ << ")");
 
-       if(filter != NULL)
+       if(filter)
                contacts_filter_destroy(filter);
-       if(query != NULL)
+       if(query)
                contacts_query_destroy(query);
 
        if(contactIds->size() != (unsigned int)record_count)
@@ -874,11 +1057,21 @@ void AddressBook::AddressBookRemoveBatch(const EventAddressBookRemoveBatchPtr &e
        KeySharePtrPair *keyPair = new KeySharePtrPair();
        keyPair->key = m_eventMapAcc;
        keyPair->addressBook = this;
+#ifdef FEATURE_EBOOK
+       errorCode = CONTACTS_ERROR_NONE;
+       if (ids) {
+               e_book_client_remove_contacts(m_ebook, ids, NULL, contactsRemoveBatchResultCallback, keyPair);
+       } else {
+               // See BatchAdd...
+               g_idle_add(contactsRemoveBatchIdleCallback, keyPair);
+       }
+#else
        errorCode = contacts_db_delete_records_async(_contacts_contact._uri, ids, count, contactsRemoveBatchResultCallback, (void*)keyPair);
        if(ids != NULL)
        {
                delete [] ids;
        }
+#endif
 /*
        if(tmpIds != NULL)
        {
@@ -942,18 +1135,18 @@ void AddressBook::OnRequestReceived(const EventAddressBookFindPtr &event)
 {
        LoggerD("entered");
 
-       contacts_query_h query = NULL;
-       contacts_filter_h filter = NULL;
-       contacts_list_h contacts_list = NULL;
-
-       ContactArrayPtr contacts = ContactArrayPtr(new ContactArray());
-
        Try
        {
-               ContactSearchEnginePtr searchEngine(new ContactSearchEngine());
+               ContactSearchEnginePtr searchEngine(new ContactSearchEngine(
+#ifdef FEATURE_EBOOK
+                                                                           m_ebook
+#endif
+                                                                           ));
 
+#ifndef FEATURE_EBOOK
                if(!m_isUnifiedAddressBook)
                        searchEngine->setAddressBookId(m_id);
+#endif
 
                if(event->getFilterIsSet())
                {
@@ -1002,15 +1195,6 @@ void AddressBook::OnRequestReceived(const EventAddressBookFindPtr &event)
                event->setExceptionCode(ExceptionCodes::PlatformException);
                event->setResult(false);
        }
-
-       if(filter != NULL)
-               contacts_filter_destroy(filter);
-
-       if(query != NULL)
-               contacts_query_destroy(query);
-
-       if(contacts_list != NULL)
-               contacts_list_destroy(contacts_list, true);
 }
 
 void AddressBook::OnRequestReceived(const EventAddressBookAddChangeListenerPtr &event)
@@ -1030,15 +1214,30 @@ void AddressBook::OnRequestReceived(const EventAddressBookAddChangeListenerPtr &
                {
                        LoggerD("Watch registered initially");
 
+#ifdef FEATURE_EBOOK
+                       GErrorCXX gerror;
+                       e_book_client_view_start(m_view, gerror);
+                       if (gerror)
+                               ThrowMsg(PlatformException, gerror.msg());
+#else
                        if(m_isUnifiedAddressBook)
                                ContactsSvcChangeListenerManagerSingleton::Instance().registerContactsChangeListener(this, -1);
                        else
                                ContactsSvcChangeListenerManagerSingleton::Instance().registerContactsChangeListener(this, m_id);
+#endif
                }
 
                m_addressBookEmitters.attach(emitter);
 
+#ifdef FEATURE_EBOOK
+               // We only use the former getWatchIdAndInc() in one place, so
+               // we might as well use a simpler local, static counter. As in
+               // getWatchIdAndInc() we don't use thread locking.
+               static int watchId;
+               long id = ++watchId;
+#else
                long id = ContactsSvcChangeListenerManagerSingleton::Instance().getWatchIdAndInc();
+#endif
                m_watchIdMap[id] = emitter->getId();
 
            event->setId(id);
@@ -1093,7 +1292,14 @@ void AddressBook::OnRequestReceived(const EventAddressBookRemoveChangeListenerPt
                {
                        LoggerD("No watcher is registered. unsubscribing from contact service.");
 
+#ifdef FEATURE_EBOOK
+                       GErrorCXX gerror;
+                       e_book_client_view_stop(m_view, gerror);
+                       if (gerror)
+                               ThrowMsg(PlatformException, gerror.msg());
+#else
                        ContactsSvcChangeListenerManagerSingleton::Instance().unregisterContactsChangeListener(this);
+#endif
                }
 
                event->setResult(true);
@@ -1129,7 +1335,6 @@ void AddressBook::OnRequestReceived(const EventAddressBookGetGroupPtr &event)
 {
        LoggerD("entered");
 
-       int errorCode = 0;
        contacts_record_h contacts_record = NULL;
 
        Try
@@ -1137,6 +1342,12 @@ void AddressBook::OnRequestReceived(const EventAddressBookGetGroupPtr &event)
                if(!event->getIdIsSet())
                        ThrowMsg(InvalidArgumentException, "Invalid group");
 
+#ifdef FEATURE_EBOOK
+               event->setResult(false);
+               event->setExceptionCode(ExceptionCodes::UnsupportedException);
+               return;
+#else
+               int errorCode = 0;
                string groupId = event->getId();
 
                int groupIdInt = ContactUtility::strToInt(groupId);
@@ -1159,6 +1370,7 @@ void AddressBook::OnRequestReceived(const EventAddressBookGetGroupPtr &event)
 
                event->setContactGroup(group);
                event->setResult(true);
+#endif
 
        }
        Catch (NotFoundException)
@@ -1189,7 +1401,7 @@ void AddressBook::OnRequestReceived(const EventAddressBookGetGroupPtr &event)
                event->setResult(false);
        }
 
-       if(contacts_record != NULL)
+       if(contacts_record)
                contacts_record_destroy(contacts_record, true);
 }
 
@@ -1197,8 +1409,6 @@ void AddressBook::OnRequestReceived(const EventAddressBookAddGroupPtr &event)
 {
        LoggerD("entered");
 
-       int errorCode = 0;
-
        contacts_record_h contacts_record = NULL;
        ContactGroupPtr group(NULL);
 
@@ -1224,7 +1434,12 @@ void AddressBook::OnRequestReceived(const EventAddressBookAddGroupPtr &event)
 
        Try
        {
-               errorCode = contacts_record_create(_contacts_group._uri, &contacts_record);
+#ifdef FEATURE_EBOOK
+               event->setResult(false);
+               event->setExceptionCode(ExceptionCodes::UnsupportedException);
+               return;
+#else
+               int errorCode = contacts_record_create(_contacts_group._uri, &contacts_record);
                if(errorCode != CONTACTS_ERROR_NONE)
                {
                        LoggerE("error code : " << errorCode);
@@ -1255,6 +1470,7 @@ void AddressBook::OnRequestReceived(const EventAddressBookAddGroupPtr &event)
 
                event->setResult(true);
                event->setExceptionCode(ExceptionCodes::None);
+#endif
        }
        Catch (PlatformException)
        {
@@ -1269,7 +1485,7 @@ void AddressBook::OnRequestReceived(const EventAddressBookAddGroupPtr &event)
                event->setExceptionCode(ExceptionCodes::UnknownException);
        }
 
-       if(contacts_record != NULL)
+       if(contacts_record)
                contacts_record_destroy(contacts_record, true);
 }
 
@@ -1277,8 +1493,6 @@ void AddressBook::OnRequestReceived(const EventAddressBookUpdateGroupPtr &event)
 {
        LoggerD("entered");
 
-       int errorCode = 0;
-
        contacts_record_h contacts_record = NULL;
        ContactGroupPtr group(NULL);
 
@@ -1315,8 +1529,13 @@ void AddressBook::OnRequestReceived(const EventAddressBookUpdateGroupPtr &event)
 
        Try
        {
+#ifdef FEATURE_EBOOK
+               event->setResult(false);
+               event->setExceptionCode(ExceptionCodes::UnsupportedException);
+               return;
+#else
                int id = ContactUtility::strToInt(group->getId());
-               errorCode = contacts_db_get_record(_contacts_group._uri, id, &contacts_record);
+               int errorCode = contacts_db_get_record(_contacts_group._uri, id, &contacts_record);
                if (errorCode == CONTACTS_ERROR_INVALID_PARAMETER)
                        ThrowMsg(NotFoundException, "Error during executing contacts_db_get_record()");
                else if (errorCode != CONTACTS_ERROR_NONE)
@@ -1338,6 +1557,7 @@ void AddressBook::OnRequestReceived(const EventAddressBookUpdateGroupPtr &event)
 
                event->setResult(true);
                event->setExceptionCode(ExceptionCodes::None);
+#endif
        }
        Catch (NotFoundException)
        {
@@ -1358,7 +1578,7 @@ void AddressBook::OnRequestReceived(const EventAddressBookUpdateGroupPtr &event)
                event->setExceptionCode(ExceptionCodes::PlatformException);
        }
 
-       if(contacts_record != NULL)
+       if(contacts_record)
                contacts_record_destroy(contacts_record, true);
 
        return;
@@ -1368,7 +1588,6 @@ void AddressBook::OnRequestReceived(const EventAddressBookRemoveGroupPtr &event)
 {
        LoggerD("entered");
 
-       int errorCode = 0;
        Try
        {
                if(!event->getContactGroupIdIsSet())
@@ -1379,12 +1598,17 @@ void AddressBook::OnRequestReceived(const EventAddressBookRemoveGroupPtr &event)
                if(!ContactUtility::checkStrIsUInt(groupIdStr))
                        ThrowMsg(InvalidArgumentException, "wrong" );
 
+#ifdef FEATURE_EBOOK
+               event->setResult(false);
+               event->setExceptionCode(ExceptionCodes::UnsupportedException);
+               return;
+#else
                int groupId = ContactUtility::strToInt(groupIdStr);
 
                if(!m_isUnifiedAddressBook)
                {
                        contacts_record_h contacts_record = NULL;
-                       errorCode = contacts_db_get_record(_contacts_group._uri, groupId, &contacts_record);
+                       int errorCode = contacts_db_get_record(_contacts_group._uri, groupId, &contacts_record);
                        if(errorCode != CONTACTS_ERROR_NONE || contacts_record == NULL)
                                ThrowMsg(PlatformException, "No group");
 
@@ -1397,7 +1621,7 @@ void AddressBook::OnRequestReceived(const EventAddressBookRemoveGroupPtr &event)
                                ThrowMsg(PlatformException, "Contact is not a member of this address book.");
                }
 
-               errorCode = contacts_db_delete_record(_contacts_group._uri, groupId);
+               int errorCode = contacts_db_delete_record(_contacts_group._uri, groupId);
                if(errorCode == CONTACTS_ERROR_INVALID_PARAMETER)
                        ThrowMsg(NotFoundException, "Error during executing contacts_db_delete_record()");
                else if (errorCode != CONTACTS_ERROR_NONE)
@@ -1405,6 +1629,7 @@ void AddressBook::OnRequestReceived(const EventAddressBookRemoveGroupPtr &event)
 
                event->setResult(true);
                event->setExceptionCode(ExceptionCodes::None);
+#endif
        }
        Catch (InvalidArgumentException)
        {
@@ -1436,13 +1661,17 @@ void AddressBook::OnRequestReceived(const EventAddressBookGetGroupsPtr &event)
 {
        LoggerD("entered");
 
-       int errorCode = 0;
-
        ContactGroupArrayPtr groups(new ContactGroupArray());
-       contacts_list_h groups_list = NULL;
+       contacts_list_h groups_list(NULL);
 
        Try
        {
+#ifdef FEATURE_EBOOK
+               event->setResult(false);
+               event->setExceptionCode(ExceptionCodes::UnsupportedException);
+               return;
+#else
+               int errorCode = 0;
 
                if(m_isUnifiedAddressBook)
                {
@@ -1578,7 +1807,7 @@ void AddressBook::OnRequestReceived(const EventAddressBookGetGroupsPtr &event)
 
                event->setContactGroups(groups);
                event->setResult(true);
-
+#endif
        }
        Catch (NotFoundException)
        {
@@ -1608,10 +1837,44 @@ void AddressBook::OnRequestReceived(const EventAddressBookGetGroupsPtr &event)
                event->setResult(false);
        }
 
-       if(groups_list != NULL)
+       if(groups_list)
                contacts_list_destroy(groups_list, true);
 }
 
+#ifdef FEATURE_EBOOK
+void AddressBook::onContactsEDSContactsAddedOrUpdated(GSList *data, void (AddressBook::*onSvc)(ContactArrayPtr &))
+{
+       GListCXX<EContact, GSList, NoopDestructor<EContact>, false> econtacts(data);
+       ContactArrayPtr contacts(new ContactArray);
+
+       BOOST_FOREACH (EContact *econtact, econtacts) {
+               Try {
+                       ContactObjectP2AConverterPtr contactObjConverter(new ContactObjectP2AConverter(contacts_record_h(econtact, ADD_REF),
+                                                                                                      m_ebook,
+                                                                                                      false) );
+                       contacts->push_back(contactObjConverter->getAbstractContact());
+               } Catch(Exception)
+               {
+                       LoggerE("Fail error on converting contact to abs contact : " << _rethrown_exception.GetMessage());
+               }
+       }
+       (this->*onSvc)(contacts);
+}
+
+void AddressBook::onContactsEDSContactsRemoved(GSList *data)
+{
+       GListCXX<char, GSList, NoopDestructor<char>, false> uids(data);
+       StringArrayPtr contactIds(new StringArray);
+
+       BOOST_FOREACH (char *uid, uids) {
+               contactIds->push_back(uid);
+       }
+       onContactsSvcContactsRemoved(contactIds);
+}
+
+
+#endif
+
 void AddressBook::onContactsSvcContactsAdded(ContactArrayPtr &contacts)
 {
        EventInfoAddressBookChangeAddedPtr contactsAdded(new EventInfoAddressBookChangeAdded());
@@ -1639,7 +1902,60 @@ void AddressBook::onContactsSvcContactsRemoved(StringArrayPtr &contactIds)
        m_addressBookEmitters.emit(listener);
 }
 
-void AddressBook::contactsAddBatchResultCallback(int error, int *ids, unsigned int count, void *user_data)
+#ifdef FEATURE_EBOOK
+gboolean AddressBook::contactsAddBatchIdleCallback(void *user_data)
+{
+       KeySharePtrPair *keyPair = (KeySharePtrPair*)user_data;
+
+       long key = keyPair->key;
+       AddressBook *addressBook = keyPair->addressBook;
+
+       delete keyPair;
+
+       addressBook->contactsAddBatchResultCallback(NULL, NULL, key);
+
+       // Not again.
+       return false;
+}
+
+gboolean AddressBook::contactsUpdateBatchIdleCallback(void *user_data)
+{
+       KeySharePtrPair *keyPair = (KeySharePtrPair*)user_data;
+
+       long key = keyPair->key;
+       AddressBook *addressBook = keyPair->addressBook;
+
+       delete keyPair;
+
+       addressBook->contactsUpdateBatchResultCallback(NULL, key);
+
+       // Not again.
+       return false;
+}
+
+gboolean AddressBook::contactsRemoveBatchIdleCallback(void *user_data)
+{
+       KeySharePtrPair *keyPair = (KeySharePtrPair*)user_data;
+
+       long key = keyPair->key;
+       AddressBook *addressBook = keyPair->addressBook;
+
+       delete keyPair;
+
+       addressBook->contactsRemoveBatchResultCallback(NULL, key);
+
+       // Not again.
+       return false;
+}
+#endif
+
+void AddressBook::contactsAddBatchResultCallback(
+#ifdef FEATURE_EBOOK
+                                                GObject *ebook, GAsyncResult *res,
+#else
+                                                int error, int *ids, unsigned int count,
+#endif
+                                                void *user_data)
 {
        LoggerD("entered");
        if(user_data == NULL)
@@ -1655,10 +1971,26 @@ void AddressBook::contactsAddBatchResultCallback(int error, int *ids, unsigned i
 
        delete keyPair;
 
+#ifdef FEATURE_EBOOK
+       GSList *ids;
+       GErrorCXX gerror;
+       if (e_book_client_add_contacts_finish((EBookClient *)ebook, res, &ids, gerror)) {
+               addressBook->contactsAddBatchResultCallback(NULL, UIDList(ids), key);
+       } else {
+               addressBook->contactsAddBatchResultCallback(gerror.msg(), NULL, key);
+       }
+#else
        addressBook->contactsAddBatchResultCallback(error, ids, count, key);
+#endif
 }
 
-void AddressBook::contactsAddBatchResultCallback(int error, int *ids, unsigned int count, long key)
+void AddressBook::contactsAddBatchResultCallback(
+#ifdef FEATURE_EBOOK
+                                                const char *error, const UIDList &ids,
+#else
+                                                int error, int *ids, unsigned int count,
+#endif
+                                                long key)
 {
        EventAddressBookAddBatchPtr event;
 
@@ -1673,7 +2005,13 @@ void AddressBook::contactsAddBatchResultCallback(int error, int *ids, unsigned i
        event = iter->second;
        m_addBatchEventMap.erase(iter);
 
-       if(error != CONTACTS_ERROR_NONE)
+       if(error !=
+#ifdef FEATURE_EBOOK
+          NULL
+#else
+          CONTACTS_ERROR_NONE
+#endif
+          )
        {
                LoggerE("contacts_db_insert_result_cb gives error : " << error);
                event->setResult(false);
@@ -1688,11 +2026,29 @@ void AddressBook::contactsAddBatchResultCallback(int error, int *ids, unsigned i
        ContactArrayPtr contacts = event->getContacts();
 #endif
 
+#ifdef FEATURE_EBOOK
+       unsigned int i;
+       UIDList::const_iterator it;
+       for (it = ids.begin(), i=0;
+            it != ids.end();
+            ++i, ++it)
+#else
        for(unsigned int i=0; i<count; i++)
+#endif
        {
+#ifdef FEATURE_EBOOK
+               EContact *econtact;
+               GErrorCXX gerror;
+               if (!e_book_client_get_contact_sync(m_ebook, *it, &econtact, NULL, gerror)) {
+                       LoggerD("Fail e_book_client_get_contact_sync: " << gerror.msg());
+                       continue;
+               }
+               contacts_record_h contacts_record(econtact, TRANSFER_REF);
+#else
                int errorCode = 0;
                int contactId = ids[i];
 
+
                contacts_record_h contacts_record = NULL;
 
                errorCode = contacts_db_get_record(_contacts_contact._uri, contactId, &contacts_record);
@@ -1701,6 +2057,7 @@ void AddressBook::contactsAddBatchResultCallback(int error, int *ids, unsigned i
                        LoggerD("Fail contacts_db_get_record error _contacts_contact._uri : " << errorCode);
                        continue;
                }
+#endif
 
 #if 0
                ContactPtr absContact(NULL);
@@ -1712,10 +2069,18 @@ void AddressBook::contactsAddBatchResultCallback(int error, int *ids, unsigned i
                {
 #if 0
                        ContactObjectP2AConverterPtr contactObjConverter(
-                                       new ContactObjectP2AConverter(contacts_record, false) );
+                                       new ContactObjectP2AConverter(contacts_record,
+#ifdef FEATURE_EBOOK
+                                                                     m_ebook,
+#endif
+                                                                     false) );
 #else
                        ContactObjectP2AConverterPtr contactObjConverter(
-                                       new ContactObjectP2AConverter(contacts_record, false, absContact) );
+                                       new ContactObjectP2AConverter(contacts_record,
+#ifdef FEATURE_EBOOK
+                                                                     m_ebook,
+#endif
+                                                                     false, absContact) );
 #endif
                        absContact = contactObjConverter->getAbstractContact();
                }
@@ -1730,7 +2095,7 @@ void AddressBook::contactsAddBatchResultCallback(int error, int *ids, unsigned i
                        contacts->push_back(absContact);
 #endif
 
-               if(contacts_record != NULL)
+               if(contacts_record)
                        contacts_record_destroy(contacts_record, true);
        }
 
@@ -1740,7 +2105,13 @@ void AddressBook::contactsAddBatchResultCallback(int error, int *ids, unsigned i
        EventRequestReceiver<EventAddressBookAddBatch>::ManualAnswer(event);
 }
 
-void AddressBook::contactsUpdateBatchResultCallback(int error, void *user_data)
+void AddressBook::contactsUpdateBatchResultCallback(
+#ifdef FEATURE_EBOOK
+                                                   GObject *ebook, GAsyncResult *res,
+#else
+                                                   int error,
+#endif
+                                                   void *user_data)
 {
        LoggerD("entered");
 
@@ -1757,10 +2128,23 @@ void AddressBook::contactsUpdateBatchResultCallback(int error, void *user_data)
 
        delete keyPair;
 
+#ifdef FEATURE_EBOOK
+       GErrorCXX gerror;
+       const char *error =
+               e_book_client_modify_contacts_finish((EBookClient *)ebook, res, gerror) ?
+               NULL :
+               gerror.msg();
+#endif
        addressBook->contactsUpdateBatchResultCallback(error, key);
 }
 
-void AddressBook::contactsUpdateBatchResultCallback(int error, long key)
+void AddressBook::contactsUpdateBatchResultCallback(
+#ifdef FEATURE_EBOOK
+                                                   const char *error,
+#else
+                                                   int error,
+#endif
+                                                   long key)
 {
        EventAddressBookUpdateBatchPtr event;
 
@@ -1775,7 +2159,13 @@ void AddressBook::contactsUpdateBatchResultCallback(int error, long key)
        event = iter->second;
        m_updateBatchEventMap.erase(iter);
 
-       if(error != CONTACTS_ERROR_NONE)
+       if(error !=
+#ifdef FEATURE_EBOOK
+          NULL
+#else
+          CONTACTS_ERROR_NONE
+#endif
+          )
        {
                LoggerE("contacts_db_result_cb gives error : " << error);
                event->setResult(false);
@@ -1789,7 +2179,13 @@ void AddressBook::contactsUpdateBatchResultCallback(int error, long key)
        EventRequestReceiver<EventAddressBookUpdateBatch>::ManualAnswer(event);
 }
 
-void AddressBook::contactsRemoveBatchResultCallback(int error, void *user_data)
+void AddressBook::contactsRemoveBatchResultCallback(
+#ifdef FEATURE_EBOOK
+                                                   GObject *ebook,  GAsyncResult *res,
+#else
+                                                   int error,
+#endif
+                                                   void *user_data)
 {
        LoggerD("entered");
 
@@ -1806,10 +2202,23 @@ void AddressBook::contactsRemoveBatchResultCallback(int error, void *user_data)
 
        delete keyPair;
 
+#ifdef FEATURE_EBOOK
+       GErrorCXX gerror;
+       const char *error =
+               e_book_client_remove_contacts_finish((EBookClient *)ebook, res, gerror) ?
+               NULL :
+               gerror.msg();
+#endif
        addressBook->contactsRemoveBatchResultCallback(error, key);
 }
 
-void AddressBook::contactsRemoveBatchResultCallback(int error, long key)
+void AddressBook::contactsRemoveBatchResultCallback(
+#ifdef FEATURE_EBOOK
+                                                   const char *error,
+#else
+                                                   int error,
+#endif
+                                                   long key)
 {
        EventAddressBookRemoveBatchPtr event;
 
@@ -1824,7 +2233,13 @@ void AddressBook::contactsRemoveBatchResultCallback(int error, long key)
        event = iter->second;
        m_removeBatchEventMap.erase(iter);
 
-       if(error != CONTACTS_ERROR_NONE)
+       if(error !=
+#ifdef FEATURE_EBOOK
+          NULL
+#else
+          CONTACTS_ERROR_NONE
+#endif
+          )
        {
                LoggerE("contacts_db_result_cb gives error : " << error);
                event->setResult(false);
index adfc5b0..ffc1ee3 100755 (executable)
@@ -30,6 +30,7 @@
 #include <Commons/Emitters.h>
 #include "IAddressBook.h"
 #include "IContact.h"
+#include <contacts.h>
 
 #include "ContactsSvcChangeListenerManager.h"
 
@@ -39,7 +40,12 @@ namespace Contact {
 class AddressBook : public IAddressBook, public IContactsSvcContactsChangeListener
 {
 private:
+#ifdef FEATURE_EBOOK
+       EBookClientCXX  m_ebook;
+       EBookClientViewCXX    m_view;
+#else
        int             m_id;
+#endif
        std::string     m_name;
        bool            m_readOnly;
        int             m_accountId;
@@ -47,12 +53,18 @@ private:
        bool            m_isUnifiedAddressBook;
 
 public:
+#ifdef FEATURE_EBOOK
+       explicit AddressBook(EBookClientCXX &ebook);
+#else
        explicit AddressBook(bool isUnified);
+#endif
        virtual ~AddressBook();
 
        virtual std::string getId() const;
+#ifndef FEATURE_EBOOK
        virtual void        setId(const std::string &value);
        void                setId(const int &value) { m_id = value; }
+#endif
        virtual std::string getName() const { return m_name; }
        virtual void            setName(const std::string &value) { m_name = value; }
        virtual bool        getReadOnly() const { return m_readOnly; }
@@ -131,6 +143,11 @@ protected:
        virtual void onContactsSvcContactsUpdated(ContactArrayPtr &contacts);
        virtual void onContactsSvcContactsRemoved(StringArrayPtr &contactIds);
 
+#ifdef FEATURE_EBOOK
+       void onContactsEDSContactsAddedOrUpdated(GSList *data, void (AddressBook::*onSvc)(ContactArrayPtr &));
+       void onContactsEDSContactsRemoved(GSList *data);
+#endif
+
 private:
        typedef WrtDeviceApis::Commons::Emitters<EventAddressBookChangeListenerEmitter> AddressBookChangedEmitter;
        AddressBookChangedEmitter       m_addressBookEmitters;
@@ -138,14 +155,55 @@ private:
        typedef std::map<long, EventAddressBookChangeListenerEmitter::IdType> WatchIdMap;
        WatchIdMap m_watchIdMap;
 
-       static void contactsAddBatchResultCallback(int error, int *ids, unsigned int count, void *user_data);
-       void contactsAddBatchResultCallback(int error, int *ids, unsigned int count, long key);
-
-       static void contactsUpdateBatchResultCallback(int error, void *user_data);
-       void contactsUpdateBatchResultCallback(int error, long key);
-
-       static void contactsRemoveBatchResultCallback(int error, void *user_data);
-       void contactsRemoveBatchResultCallback(int error, long key);
+#ifdef FEATURE_EBOOK
+       static gboolean contactsAddBatchIdleCallback(void *user_data);
+       static gboolean contactsUpdateBatchIdleCallback(void *user_data);
+       static gboolean contactsRemoveBatchIdleCallback(void *user_data);
+#endif
+       static void contactsAddBatchResultCallback(
+#ifdef FEATURE_EBOOK
+                                                  GObject *ebook, GAsyncResult *res,
+#else
+                                                  int error, int *ids, unsigned int count,
+#endif
+                                                  void *user_data);
+       void contactsAddBatchResultCallback(
+#ifdef FEATURE_EBOOK
+                                           const char *error, const UIDList &ids,
+#else
+                                           int error, int *ids, unsigned int count,
+#endif
+                                           long key);
+
+       static void contactsUpdateBatchResultCallback(
+#ifdef FEATURE_EBOOK
+                                                     GObject *ebook, GAsyncResult *res,
+#else
+                                                     int error,
+#endif
+                                                     void *user_data);
+       void contactsUpdateBatchResultCallback(
+#ifdef FEATURE_EBOOK
+                                              const char *error,
+#else
+                                              int error,
+#endif
+                                              long key);
+
+       static void contactsRemoveBatchResultCallback(
+#ifdef FEATURE_EBOOK
+                                                  GObject *ebook, GAsyncResult *res,
+#else
+                                                  int error,
+#endif
+                                                  void *user_data);
+       void contactsRemoveBatchResultCallback(
+#ifdef FEATURE_EBOOK
+                                              const char *error,
+#else
+                                              int error,
+#endif
+                                              long key);
 
        struct KeySharePtrPair
        {
index 5dc9cae..647e13b 100755 (executable)
@@ -3,7 +3,12 @@ SET(DESTINATION_NAME ${contact_dest})
 SET(TARGET_IMPL_NAME ${contact_impl})
 SET(TARGET_CONFIG_NAME ${contact_config})
 
-PKG_CHECK_MODULES(platform_pkgs_contact REQUIRED contacts-service2 libpcrecpp)
+IF(WITH_EBOOK)
+    PKG_CHECK_MODULES(platform_pkgs_contact REQUIRED libebook-1.2 libpcrecpp)
+    INCLUDE_DIRECTORIES(contacts2ebook)
+ELSE(WITH_EBOOK)
+    PKG_CHECK_MODULES(platform_pkgs_contact REQUIRED contacts-service2 libpcrecpp)
+ENDIF(WITH_EBOOK)
 
 ADD_DEFINITIONS("-fvisibility=hidden")
 
index 93e00f5..1bccb56 100644 (file)
@@ -81,7 +81,7 @@ Contact::Contact()
 
 Contact::~Contact()
 {
-       if (m_platformContactObjectList != NULL)
+       if (m_platformContactObjectList)
                contacts_list_destroy(m_platformContactObjectList, true);
 
        if(numbersJSObjIsSet()){
@@ -136,8 +136,6 @@ Contact::~Contact()
 string Contact::convertToString(const string &format)
 {
        LoggerD("entered");
-       int errorCode = 0;
-       char *vcard_stream = NULL;
 
        if(!format.empty() && format != "VCARD_30")
                ThrowMsg(ConversionException, "format must be 'VCARD_30'");
@@ -147,18 +145,28 @@ string Contact::convertToString(const string &format)
 
        contacts_record_h contacts_record = NULL;
        Try {
-               contactObjConverter = ContactObjectA2PConverterPtr(new ContactObjectA2PConverter(thisObj, true) );
+               contactObjConverter = ContactObjectA2PConverterPtr(new ContactObjectA2PConverter(thisObj,
+#ifdef FEATURE_EBOOK
+                                                                                                EBookClientCXX(),
+#endif
+                                                                                                true) );
                contacts_record = contactObjConverter->getPlatformContact();
        } Catch (Exception) {
                ThrowMsg(PlatformException, "Fail to extract contact to platform object.");
        }
-       errorCode = contacts_vcard_make_from_contact(contacts_record, &vcard_stream);
+#ifdef FEATURE_EBOOK
+       PlainGStr vcard(e_vcard_to_string(E_VCARD(contacts_record.get()), EVC_FORMAT_VCARD_30));
+       string result(vcard);
+#else
+       char *vcard_stream = NULL;
+       int errorCode = contacts_vcard_make_from_contact(contacts_record, &vcard_stream);
        if(errorCode != CONTACTS_ERROR_NONE)
                ThrowMsg(PlatformException, "Fail to convert to vCard.");
 
        string result((char *)vcard_stream);
 
        free(vcard_stream);
+#endif
 
        return result;
 }
@@ -166,10 +174,15 @@ string Contact::convertToString(const string &format)
 void Contact::setContactFromString(const std::string &vObjectStr)
 {
        LoggerD("entered");
+#ifdef FEATURE_EBOOK
+       contacts_record_h contacts_record(e_contact_new_from_vcard(vObjectStr.c_str()), TRANSFER_REF);
+       contacts_list_h contacts_list;
+       contacts_list.push_front(contacts_record.ref());
+#else
        int errorCode = 0;
        const char *vcard_stream = vObjectStr.c_str();
 
-       contacts_list_h contacts_list = NULL;
+       contacts_list_h contacts_list(NULL);
        errorCode = contacts_vcard_parse_to_contacts(vcard_stream, &contacts_list);
        if(errorCode == CONTACTS_ERROR_INVALID_PARAMETER)
                ThrowMsg(InvalidArgumentException, "Invalid vCard string.");
@@ -192,18 +205,29 @@ void Contact::setContactFromString(const std::string &vObjectStr)
                contacts_list_destroy(contacts_list, true);
                ThrowMsg(InvalidArgumentException, "Invalid vCard string. (3)");
        }
+#endif
 
        ContactObjectP2AConverterPtr contactObjConverter(NULL);
        Try {
                ContactPtr thisObj = SharedFromThis();
-               contactObjConverter = ContactObjectP2AConverterPtr(new ContactObjectP2AConverter(contacts_record, true, thisObj) );
+               contactObjConverter = ContactObjectP2AConverterPtr(new ContactObjectP2AConverter(contacts_record,
+#ifdef FEATURE_EBOOK
+                                                                                                EBookClientCXX(),
+#endif
+                                                                                                true, thisObj) );
                contactObjConverter->getAbstractContact();
        } Catch (Exception) {
                ThrowMsg(PlatformException, "Fail to extract contact from platform object.");
        }
 
        m_platformContactObject = contacts_record;
-       m_platformContactObjectList = contacts_list;
+#ifdef FEATURE_EBOOK
+       // TODO: at some point figure out how we can allow std::swap
+       // with our contacts_list_h and then remove this ifdef.
+       m_platformContactObjectList.swap(contacts_list);
+#else
+       std::swap(m_platformContactObjectList, contacts_list);
+#endif
 }
 
 void Contact::setNumbersJSObj(bool value, JSObjectRef initObj)
index 3dd4aca..fd55345 100755 (executable)
@@ -51,10 +51,12 @@ ContactManager::ContactManager() : m_eventMapAcc(0)
 
 ContactManager::~ContactManager()
 {
+#ifndef FEATURE_EBOOK
        if(m_contactManagerEmitters.size() != 0)
        {
                ContactsSvcChangeListenerManagerSingleton::Instance().unregisterPersonsChangeListener(this);
        }
+#endif
 }
 
 void ContactManager::OnRequestReceived(const EventContactManagerGetAddressBookPtr &event)
@@ -195,7 +197,6 @@ void ContactManager::OnRequestReceived(const EventContactManagerGetPtr &event)
 {
        LoggerD("entered");
 
-       int errorCode = 0;
        contacts_record_h contacts_record = NULL;
 
        Try     {
@@ -204,6 +205,11 @@ void ContactManager::OnRequestReceived(const EventContactManagerGetPtr &event)
 
                string personId = event->getId();
 
+#ifdef FEATURE_EBOOK
+               ThrowMsg(UnsupportedException, "Person concept not supported.");
+#else
+
+                int errorCode = 0;
                int personIdInt = ContactUtility::strToInt(personId);
 
                errorCode = contacts_db_get_record(_contacts_person._uri, personIdInt, &contacts_record);
@@ -211,6 +217,7 @@ void ContactManager::OnRequestReceived(const EventContactManagerGetPtr &event)
                {
                        ThrowMsg(NotFoundException, "No person : " << errorCode);
                }
+#endif
                PersonPtr person = PersonPtr(new Person());
 
                ContactsSvcObjectConverter::convertToAbstract(contacts_record, person);
@@ -239,7 +246,7 @@ void ContactManager::OnRequestReceived(const EventContactManagerGetPtr &event)
                event->setResult(false);
        }
 
-       if(contacts_record != NULL)
+       if(contacts_record)
                contacts_record_destroy(contacts_record, true);
 }
 
@@ -247,8 +254,6 @@ void ContactManager::OnRequestReceived(const EventContactManagerUpdatePtr &event
 {
        LoggerD("entered");
 
-       int errorCode = 0;
-
        contacts_record_h contacts_record = NULL;
        PersonPtr person(NULL);
 
@@ -272,6 +277,13 @@ void ContactManager::OnRequestReceived(const EventContactManagerUpdatePtr &event
 
        Try
        {
+#ifdef FEATURE_EBOOK
+               event->setResult(false);
+               event->setExceptionCode(ExceptionCodes::UnsupportedException);
+               return;
+#else
+               int errorCode = 0;
+
                int id = ContactUtility::strToInt(person->getId());
                errorCode = contacts_db_get_record(_contacts_person._uri, id, &contacts_record);
                if (errorCode == CONTACTS_ERROR_INVALID_PARAMETER)
@@ -280,9 +292,11 @@ void ContactManager::OnRequestReceived(const EventContactManagerUpdatePtr &event
                        LoggerE("error code : " << errorCode);
                        ThrowMsg(PlatformException, "Error during executing contacts_db_get_record()");
                }
+#endif
 
                ContactsSvcObjectConverter::convertToPlatform(person, contacts_record);
 
+#ifndef FEATURE_EBOOK
                errorCode = contacts_db_update_record(contacts_record);
                if (errorCode == CONTACTS_ERROR_INVALID_PARAMETER)
                        ThrowMsg(NotFoundException, "Error during executing contacts_db_update_record()");
@@ -290,6 +304,7 @@ void ContactManager::OnRequestReceived(const EventContactManagerUpdatePtr &event
                        LoggerE("error code : " << errorCode);
                        ThrowMsg(PlatformException, "Error during executing contacts_db_update_record()");
                }
+#endif
 
                event->setResult(true);
                event->setExceptionCode(ExceptionCodes::None);
@@ -311,7 +326,7 @@ void ContactManager::OnRequestReceived(const EventContactManagerUpdatePtr &event
                event->setExceptionCode(ExceptionCodes::PlatformException);
        }
 
-       if(contacts_record != NULL)
+       if(contacts_record)
                contacts_record_destroy(contacts_record, true);
 
        return;
@@ -321,7 +336,7 @@ void ContactManager::managerUpdateBatch(const EventContactManagerUpdateBatchPtr
 {
        LoggerD("entered");
        int errorCode = 0;
-       contacts_list_h contacts_list = NULL;
+       contacts_list_h contacts_list(NULL);
        PersonArrayPtr persons(NULL);
 
        if(!event->getPersonsIsSet())
@@ -333,11 +348,15 @@ void ContactManager::managerUpdateBatch(const EventContactManagerUpdateBatchPtr
 
        errorCode = contacts_list_create(&contacts_list);
        if(errorCode != CONTACTS_ERROR_NONE){
-               if(contacts_list != NULL)
+               if(contacts_list)
                        contacts_list_destroy(contacts_list, false);
                ThrowMsg(PlatformException, "Fail to create contacts_list_h");
        }
 
+#ifdef FEATURE_EBOOK
+       ThrowMsg(UnsupportedException, "Person concept not supported.");
+#endif
+
        for(PersonArray::iterator i = persons->begin(); i != persons->end(); i++)
        {
                contacts_record_h contacts_record = NULL;
@@ -345,12 +364,14 @@ void ContactManager::managerUpdateBatch(const EventContactManagerUpdateBatchPtr
 
                Try
                {
+#ifndef FEATURE_EBOOK
                        int personIdInt = ContactUtility::strToInt(person->getId());
                        errorCode = contacts_db_get_record(_contacts_person._uri, personIdInt, &contacts_record);
                        if(errorCode != CONTACTS_ERROR_NONE)
                        {
                                ThrowMsg(NotFoundException, "No person");
                        }
+#endif
 
                        ContactsSvcObjectConverter::convertToPlatform(person, contacts_record);
 
@@ -362,7 +383,7 @@ void ContactManager::managerUpdateBatch(const EventContactManagerUpdateBatchPtr
                }
                Catch(NotFoundException)
                {
-                       if(contacts_list != NULL)
+                       if(contacts_list)
                                contacts_list_destroy(contacts_list, false);
                        ThrowMsg(NotFoundException, "Error during converting contact object");
 //                             LoggerE("Error during converting person object : " << _rethrown_exception.GetMessage());
@@ -370,7 +391,7 @@ void ContactManager::managerUpdateBatch(const EventContactManagerUpdateBatchPtr
                }
                Catch(PlatformException)
                {
-                       if(contacts_list != NULL)
+                       if(contacts_list)
                                contacts_list_destroy(contacts_list, false);
                        ThrowMsg(NotFoundException, "Error during converting contact object");
 //                             LoggerE("Error during converting person object : " << _rethrown_exception.GetMessage());
@@ -381,17 +402,18 @@ void ContactManager::managerUpdateBatch(const EventContactManagerUpdateBatchPtr
        KeySharePtrPair *keyPair = new KeySharePtrPair();
        keyPair->key = m_eventMapAcc;
        keyPair->contactManager = this;
+#ifndef FEATURE_EBOOK
        errorCode = contacts_db_update_records_async(contacts_list, personsUpdateBatchResultCallback, (void*)keyPair);
+#endif
        if(errorCode != CONTACTS_ERROR_NONE)
        {
                delete keyPair;
-               if(contacts_list != NULL)
+               if(contacts_list)
                        contacts_list_destroy(contacts_list, false);
                ThrowMsg(PlatformException, "Error during contacts_db_update_records_async");
        }
 
        errorCode = contacts_list_destroy(contacts_list, true);
-       contacts_list = NULL;
        if(errorCode != CONTACTS_ERROR_NONE)
        {
                delete keyPair;
@@ -467,6 +489,11 @@ void ContactManager::OnRequestReceived(const EventContactManagerRemovePtr &event
                        ThrowMsg(InvalidArgumentException, "wrong" );
                }
 
+#ifdef FEATURE_EBOOK
+               event->setResult(false);
+               event->setExceptionCode(ExceptionCodes::UnsupportedException);
+               return;
+#else
                int errorCode = contacts_db_delete_record(_contacts_person._uri, personId);
                if(errorCode == CONTACTS_ERROR_INVALID_PARAMETER)
                        ThrowMsg(NotFoundException, "Error during executing contacts_db_delete_record()");
@@ -474,6 +501,7 @@ void ContactManager::OnRequestReceived(const EventContactManagerRemovePtr &event
                        ThrowMsg(NotFoundException, "Error during executing contacts_db_delete_record()");
                else if (errorCode != CONTACTS_ERROR_NONE)
                        ThrowMsg(PlatformException, "Error during executing contacts_db_delete_record()");
+#endif
 
                event->setResult(true);
                event->setExceptionCode(ExceptionCodes::None);
@@ -559,6 +587,9 @@ void ContactManager::managerRemoveBatch(const EventContactManagerRemoveBatchPtr
                }
        }
 
+#ifdef FEATURE_EBOOK
+       ThrowMsg(UnsupportedException, "Person concept not supported.");
+#else
        KeySharePtrPair *keyPair = new KeySharePtrPair();
        keyPair->key = m_eventMapAcc;
        keyPair->contactManager = this;
@@ -579,6 +610,7 @@ void ContactManager::managerRemoveBatch(const EventContactManagerRemoveBatchPtr
        m_removeBatchEventMap.insert(keyEventPair);
 
        m_eventMapAcc++;
+#endif
 }
 
 void ContactManager::OnRequestReceived(const EventContactManagerRemoveBatchPtr &event)
@@ -627,6 +659,11 @@ void ContactManager::OnRequestReceived(const EventContactManagerFindPtr &event)
        LoggerD("entered");
 
        Try     {
+#ifdef FEATURE_EBOOK
+               event->setResult(false);
+               event->setExceptionCode(ExceptionCodes::UnsupportedException);
+               return;
+#else
                PersonSearchEnginePtr searchEngine(new PersonSearchEngine());
 
                if(event->getFilterIsSet())
@@ -649,6 +686,7 @@ void ContactManager::OnRequestReceived(const EventContactManagerFindPtr &event)
 
                event->setPersons(searchEngine->getResult());
                event->setResult(true);
+#endif
 
        } Catch (NotFoundException) {
                LoggerE("Person doesn't exist : " << _rethrown_exception.GetMessage());
@@ -684,6 +722,12 @@ void ContactManager::OnRequestReceived(const EventContactManagerAddChangeListene
                if(emitter == NULL)
                        ThrowMsg(InvalidArgumentException, "Invalid arguments.");
 
+#ifdef FEATURE_EBOOK
+               event->setResult(false);
+               event->setExceptionCode(ExceptionCodes::UnsupportedException);
+               return;
+#else
+
                if(m_contactManagerEmitters.size() == 0)
                {
                        LoggerD("Watch registered initially");
@@ -698,6 +742,7 @@ void ContactManager::OnRequestReceived(const EventContactManagerAddChangeListene
 
            event->setId(id);
                event->setResult(true);
+#endif
 
        } Catch (NotFoundException) {
                LoggerE("Person doesn't exist : " << _rethrown_exception.GetMessage());
@@ -740,12 +785,18 @@ void ContactManager::OnRequestReceived(const EventContactManagerRemoveChangeList
 
                m_watchIdMap.erase(id);
 
+#ifdef FEATURE_EBOOK
+               event->setResult(false);
+               event->setExceptionCode(ExceptionCodes::UnsupportedException);
+               return;
+#else
                if(m_contactManagerEmitters.size() == 0)
                {
                        LoggerD("No watcher is registered. unsubscribing from person service.");
 
                        ContactsSvcChangeListenerManagerSingleton::Instance().unregisterPersonsChangeListener(this);
                }
+#endif
 
                event->setResult(true);
 
index c71d52d..ff9d777 100755 (executable)
@@ -23,6 +23,7 @@
  */
 
 #include "ContactObjectA2PConverter.h"
+#include "ContactObjectP2AConverter.h"
 
 #include <Commons/Exception.h>
 #include "ContactUtility.h"
@@ -34,11 +35,19 @@ namespace Contact {
 using namespace WrtDeviceApis::Commons;
 using namespace std;
 
+#ifndef FEATURE_EBOOK
 static const char *EMPTY_STRING = "";
+#endif
 
 ContactObjectA2PConverter::ContactObjectA2PConverter(const ContactPtr &abstractContact,
+#ifdef FEATURE_EBOOK
+               EBookClientCXX ebook,
+#endif
                bool forScratch) :
                m_abstractContact(abstractContact),
+#ifdef FEATURE_EBOOK
+               m_ebook(ebook),
+#endif
                m_platformContact(NULL),
                m_forScratch(forScratch),
                m_convertFinished(false),
@@ -47,9 +56,15 @@ ContactObjectA2PConverter::ContactObjectA2PConverter(const ContactPtr &abstractC
 }
 
 ContactObjectA2PConverter::ContactObjectA2PConverter(const ContactPtr &abstractContact,
+#ifdef FEATURE_EBOOK
+               EBookClientCXX ebook,
+#endif
                bool forScratch,
                contacts_record_h platformContact) :
                m_abstractContact(abstractContact),
+#ifdef FEATURE_EBOOK
+               m_ebook(ebook),
+#endif
                m_platformContact(platformContact),
                m_forScratch(forScratch),
                m_convertFinished(false),
@@ -59,7 +74,7 @@ ContactObjectA2PConverter::ContactObjectA2PConverter(const ContactPtr &abstractC
 
 ContactObjectA2PConverter::~ContactObjectA2PConverter()
 {
-       if(m_platformContactOwnership && m_platformContact != NULL)
+       if(m_platformContactOwnership && m_platformContact)
        {
                contacts_record_destroy(m_platformContact, true);
                m_platformContact = NULL;
@@ -71,29 +86,42 @@ contacts_record_h ContactObjectA2PConverter::getPlatformContact()
 {
        LoggerD("enter");
 
-       int errorCode = 0;
-
        if(m_abstractContact == NULL)
        {
                LoggerE("Abstract contact object did not set");
                ThrowMsg(InvalidArgumentException, "Abstract contact object did not set");
        }
 
-       if(m_platformContact == NULL)
+       if(!m_platformContact)
        {
                if(m_abstractContact->getIdIsSet() && (m_forScratch == false))
                {
+#ifdef FEATURE_EBOOK
+                       if (!m_ebook)
+                               ThrowMsg(UnknownException, "cannot create new contact without address book");
+                       EContact *econtact;
+                       GErrorCXX gerror;
+                       if (!e_book_client_get_contact_sync(m_ebook, m_abstractContact->getId().c_str(),
+                                                           &econtact, NULL, gerror))
+                               ThrowMsg(UnknownException, "e_book_client_get_contact_sync: " << gerror.msg());
+                       m_platformContact.take(econtact);
+#else
                        int id = ContactUtility::strToInt(m_abstractContact->getId());
-                       errorCode = contacts_db_get_record(_contacts_contact._uri, id, &m_platformContact);
+                       int errorCode = contacts_db_get_record(_contacts_contact._uri, id, &m_platformContact);
                        if(errorCode != CONTACTS_ERROR_NONE)
                                ThrowMsg(UnknownException, "error on contacts_db_get_record (errorCode:" << errorCode << ")");
+#endif
                }
                else
                {
                        LoggerD("New platform object has been created");
-                       errorCode = contacts_record_create(_contacts_contact._uri, &m_platformContact);
+#ifdef FEATURE_EBOOK
+                       m_platformContact.take(e_contact_new());
+#else
+                       int errorCode = contacts_record_create(_contacts_contact._uri, &m_platformContact);
                        if(errorCode != CONTACTS_ERROR_NONE)
                                ThrowMsg(UnknownException, "error on contacts_record_create (errorCode:" << errorCode << ")");
+#endif
                }
 
                m_platformContactOwnership = true;
@@ -132,6 +160,7 @@ void ContactObjectA2PConverter::convertToPlatformObject()
 
 void ContactObjectA2PConverter::importBaseInfoValue()
 {
+#ifndef FEATURE_EBOOK
        int errorCode = 0;
        contacts_record_h child_record = NULL;
 
@@ -139,8 +168,20 @@ void ContactObjectA2PConverter::importBaseInfoValue()
        char *oldValueStr = NULL;
        string abstractValueStr;
        string realPath;
+#endif
 
        // Contact.photoURI
+#ifdef FEATURE_EBOOK
+       if (!m_abstractContact->getPhotoURIIsSet()) {
+               EContactFieldCXX<E_CONTACT_PHOTO>::set(m_platformContact, NULL);
+       } else {
+               EContactPhoto photo;
+               photo.type = E_CONTACT_PHOTO_TYPE_URI;
+               string uri = m_abstractContact->getPhotoURI();
+               photo.data.uri = const_cast<char *>(uri.c_str());
+               EContactFieldCXX<E_CONTACT_PHOTO>::set(m_platformContact, &photo);
+       }
+#else
        if(!m_abstractContact->getPhotoURIIsSet() || m_abstractContact->getPhotoURI().empty())
        {
                errorCode = contacts_record_create(_contacts_image._uri, &child_record);
@@ -186,8 +227,10 @@ void ContactObjectA2PConverter::importBaseInfoValue()
                if(is_first)
                        contacts_record_add_child_record(m_platformContact, _contacts_contact.image, child_record);
        }
+#endif
 
        // Contact.ringtoneURI
+#ifndef FEATURE_EBOOK
        newValueStr = NULL;
        oldValueStr = NULL;
        contacts_record_get_str_p(m_platformContact, _contacts_contact.ringtone_path, &oldValueStr);
@@ -212,12 +255,15 @@ void ContactObjectA2PConverter::importBaseInfoValue()
                        ThrowMsg(PlatformException, "importing ringtoneURI E (err:" << errorCode);
                }
        }
+#endif
 }
 
 void ContactObjectA2PConverter::importNameValue()
 {
+#ifndef FEATURE_EBOOK
        int errorCode = 0;
        contacts_record_h child_record = NULL;
+#endif
 
        ContactNamePtr contactName = m_abstractContact->getName();
        if(contactName == NULL ||
@@ -230,13 +276,31 @@ void ContactObjectA2PConverter::importNameValue()
                        && ( !contactName->getSuffixIsSet() || contactName->getSuffix().empty() )
                        && ( !contactName->getPrefixIsSet() || contactName->getPrefix().empty() ) ) )
        {
+#ifdef FEATURE_EBOOK
+               EContactFieldCXX<E_CONTACT_NAME>::set(m_platformContact, NULL);
+#else
                errorCode = contacts_record_create(_contacts_name._uri, &child_record);
                if(errorCode != CONTACTS_ERROR_NONE)
                        ThrowMsg(UnknownException, "creating name value A (errorCode:" << errorCode << ")");
                contacts_record_add_child_record(m_platformContact, _contacts_contact.name, child_record);
+#endif
                return;
        }
 
+#ifdef FEATURE_EBOOK
+       EContactName name;
+       string first = contactName->getFirstName();
+       string middle = contactName->getMiddleName();
+       string last = contactName->getLastName();
+       string prefix = contactName->getPrefix();
+       string suffix = contactName->getSuffix();
+       name.given = contactName->getFirstNameIsSet() ? const_cast<char *>(first.c_str()) : NULL;
+       name.additional = contactName->getMiddleNameIsSet() ? const_cast<char *>(middle.c_str()) : NULL;
+       name.family = contactName->getLastNameIsSet() ? const_cast<char *>(last.c_str()) : NULL;
+       name.prefixes = contactName->getPrefixIsSet() ? const_cast<char *>(prefix.c_str()) : NULL;
+       name.suffixes = contactName->getSuffixIsSet() ? const_cast<char *>(suffix.c_str()) : NULL;
+       EContactFieldCXX<E_CONTACT_NAME>::set(m_platformContact, &name);
+#else
        errorCode = contacts_record_get_child_record_at_p(m_platformContact, _contacts_contact.name, 0, &child_record);
        if(errorCode != CONTACTS_ERROR_NONE || child_record == NULL)
        {
@@ -252,8 +316,10 @@ void ContactObjectA2PConverter::importNameValue()
        }
 
        contacts_record_add_child_record(m_platformContact, _contacts_contact.name, child_record);
+#endif
 }
 
+#ifndef FEATURE_EBOOK
 void ContactObjectA2PConverter::importNameValueToExistingValue(contacts_record_h child_record, ContactNamePtr &contactName)
 {
        int errorCode = 0;
@@ -577,9 +643,11 @@ void ContactObjectA2PConverter::importNameValueToNewValue(contacts_record_h chil
                }
        }
 }
+#endif
 
 void ContactObjectA2PConverter::importCompanyList()
 {
+#ifndef FEATURE_EBOOK
        int errorCode = 0;
        contacts_record_h child_record = NULL;
        unsigned int record_count = 0;
@@ -602,16 +670,36 @@ void ContactObjectA2PConverter::importCompanyList()
 
                child_record = NULL;
        }
+#endif
 
        ContactOrganizationArrayPtr organizations = m_abstractContact->getOrganizations();
        if(organizations->size() == 0)
+       {
+#ifdef FEATURE_EBOOK
+               EContactFieldCXX<E_CONTACT_ORG>::set(m_platformContact, NULL);
+               EContactFieldCXX<E_CONTACT_ORG_UNIT>::set(m_platformContact, NULL);
+               EContactFieldCXX<E_CONTACT_TITLE>::set(m_platformContact, NULL);
+               EContactFieldCXX<E_CONTACT_ROLE>::set(m_platformContact, NULL);
+               EContactFieldCXX<E_CONTACT_ASSISTANT>::set(m_platformContact, NULL);
+#endif
                return;
+       }
 
        ContactOrganizationArray::iterator organizationsIter = organizations->begin();
        for(; organizationsIter != organizations->end(); organizationsIter++)
        {
                ContactOrganizationPtr organization = *organizationsIter;
 
+#ifdef FEATURE_EBOOK
+               EContactFieldCXX<E_CONTACT_ORG>::setString(m_platformContact, organization->getName(), organization->getNameIsSet());
+               EContactFieldCXX<E_CONTACT_ORG_UNIT>::setString(m_platformContact, organization->getDepartment(), organization->getDepartmentIsSet());
+               EContactFieldCXX<E_CONTACT_TITLE>::setString(m_platformContact, organization->getTitle(), organization->getTitleIsSet());
+               EContactFieldCXX<E_CONTACT_ROLE>::setString(m_platformContact, organization->getRole(), organization->getRoleIsSet());
+               EContactFieldCXX<E_CONTACT_ASSISTANT>::setString(m_platformContact, organization->getAssistant(), organization->getAssistantIsSet());
+
+               // Only one ORG supported.
+               break;
+#else
                child_record = NULL;
 
                errorCode = contacts_record_create(_contacts_company._uri, &child_record);
@@ -809,11 +897,13 @@ void ContactObjectA2PConverter::importCompanyList()
                        contacts_record_destroy(child_record, true);
                        continue;
                }
+#endif
        }
 }
 
 void ContactObjectA2PConverter::importNoteList()
 {
+#ifndef FEATURE_EBOOK
        int errorCode = 0;
        contacts_record_h child_record = NULL;
        unsigned int record_count = 0;
@@ -836,16 +926,27 @@ void ContactObjectA2PConverter::importNoteList()
 
                child_record = NULL;
        }
+#endif
 
        StringArrayPtr notes = m_abstractContact->getNotes();
        if(notes->size() == 0)
+       {
+#ifdef FEATURE_EBOOK
+               EContactFieldCXX<E_CONTACT_NOTE>::set(m_platformContact, NULL);
+#endif
                return;
+       }
 
        StringArray::iterator notesIter = notes->begin();
        for(; notesIter != notes->end(); notesIter++)
        {
                string note = *notesIter;
 
+#ifdef FEATURE_EBOOK
+               EContactFieldCXX<E_CONTACT_NOTE>::set(m_platformContact, note.c_str());
+               // Only one note supported.
+               break;
+#else
                child_record = NULL;
 
                if(note.empty())
@@ -875,11 +976,70 @@ void ContactObjectA2PConverter::importNoteList()
                        contacts_record_destroy(child_record, true);
                        continue;
                }
+#endif
        }
 }
 
+#ifdef FEATURE_EBOOK
+
+template<class E, string (E::*getter)()> struct CopyStringValue
+{
+       typedef void (*Copy_t)(EVCard *vcard, EVCardAttribute *attribute, E &e);
+       static void copy(EVCard *vcard, EVCardAttribute *attribute, E &e)
+       {
+               string value = (e.*getter)();
+               e_vcard_append_attribute_with_value(vcard, attribute, value.c_str());
+       }
+};
+
+// Implements both importNumberList and importEmailList.
+template<class EArray, class T, class GT, class C>
+void importList(contacts_record_h &record, const EArray &array,
+               const char *property,
+               const Types<T> *types,
+               GT getTypes, // TArray (E::*getTypes)() const,
+               C copyValue
+               )
+{
+       // Remove all and add back.
+       e_vcard_remove_attributes(E_VCARD(record.get()), NULL, property);
+
+       BOOST_FOREACH (const typename EArray::value_type &entry, array) {
+               EVCardAttribute *attribute = e_vcard_attribute_new(NULL, property);
+               EVCardAttributeParam *parameter = e_vcard_attribute_param_new("TYPE");
+               BOOST_FOREACH (T typeEnum, *((*entry).*getTypes)()) {
+                       for (const Types<T> *type = types;
+                            type->typeString;
+                            ++type) {
+                               if (type->enumVal == typeEnum) {
+                                       e_vcard_attribute_param_add_value(parameter, type->typeString);
+                                       break;
+                               }
+                       }
+               }
+               e_vcard_attribute_add_param(attribute, parameter);
+               // Takes ownership of parameter and attribute instances.
+               copyValue(E_VCARD(record.get()), attribute, *entry);
+       }
+}
+#endif
+
+#ifdef FEATURE_EBOOK
+static void CopyNumber(EVCard *vcard, EVCardAttribute *attribute, const ContactPhoneNumber &number)
+{
+       string value = number.getNumber();
+       e_vcard_append_attribute_with_value(vcard, attribute, value.c_str());
+}
+#endif
+
 void ContactObjectA2PConverter::importNumberList()
 {
+#ifdef FEATURE_EBOOK
+       importList(m_platformContact, *m_abstractContact->getPhoneNumbers(),
+                  EVC_TEL, EDSTelTypes,
+                  &ContactPhoneNumber::getTypes,
+                  CopyNumber);
+#else
        int errorCode = 0;
        contacts_record_h child_record = NULL;
        unsigned int record_count = 0;
@@ -1020,10 +1180,25 @@ void ContactObjectA2PConverter::importNumberList()
                        continue;
                }
        }
+#endif
 }
 
+#ifdef FEATURE_EBOOK
+static void CopyEmail(EVCard *vcard, EVCardAttribute *attribute, const ContactEmailAddress &email)
+{
+       string value = email.getEmail();
+       e_vcard_append_attribute_with_value(vcard, attribute, value.c_str());
+}
+#endif
+
 void ContactObjectA2PConverter::importEmailList()
 {
+#ifdef FEATURE_EBOOK
+       importList(m_platformContact, *m_abstractContact->getEmails(),
+                  EVC_EMAIL, EDSEmailTypes,
+                  &ContactEmailAddress::getTypes,
+                  CopyEmail);
+#else
        int errorCode = 0;
        contacts_record_h child_record = NULL;
        unsigned int record_count = 0;
@@ -1141,10 +1316,14 @@ void ContactObjectA2PConverter::importEmailList()
                        continue;
                }
        }
+#endif
 }
 
 void ContactObjectA2PConverter::importGrouprelList()
 {
+#ifdef FEATURE_EBOOK
+       // Not supported.
+#else
        int errorCode = 0;
        contacts_record_h child_record = NULL;
        unsigned int record_count = 0;
@@ -1216,10 +1395,26 @@ void ContactObjectA2PConverter::importGrouprelList()
                        continue;
                }
        }
+#endif
 }
 
 void ContactObjectA2PConverter::importEventList()
 {
+#ifdef FEATURE_EBOOK
+       // E_CONTACT_ANNIVERSARY not supported by mapping to JS,
+       // don't touch it.
+
+       if (m_abstractContact->getBirthdayIsSet()) {
+               tm birthdayTm = m_abstractContact->getBirthday();
+               EContactDate bday;
+               bday.year = birthdayTm.tm_year;
+               bday.month = birthdayTm.tm_mon;
+               bday.day = birthdayTm.tm_mday;
+               EContactFieldCXX<E_CONTACT_BIRTH_DATE>::set(m_platformContact, &bday);
+       } else {
+               EContactFieldCXX<E_CONTACT_BIRTH_DATE>::set(m_platformContact, NULL);
+       }
+#else
        int errorCode = 0;
        contacts_record_h child_record = NULL;
        unsigned int record_count = 0;
@@ -1249,8 +1444,10 @@ void ContactObjectA2PConverter::importEventList()
        importEventListBirthday();
 
        importEventListAnniversary();
+#endif
 }
 
+#ifndef FEATURE_EBOOK
 void ContactObjectA2PConverter::importEventListBirthday()
 {
        int errorCode = 0;
@@ -1371,9 +1568,30 @@ void ContactObjectA2PConverter::importEventListAnniversary()
                }
        }
 }
+#endif
+
+#ifdef FEATURE_EBOOK
+static void CopyAddress(EVCard *vcard, EVCardAttribute *attribute, const ContactAddress &address)
+{
+       e_vcard_append_attribute_with_values(vcard, attribute,
+                                            address.getPostalCode().c_str(),
+                                            address.getRegion().c_str(),
+                                            address.getCity().c_str(),
+                                            address.getStreetAddress().c_str(),
+                                            address.getAdditionalInformation().c_str(),
+                                            address.getCountry().c_str(),
+                                            (void *)NULL);
+}
+#endif
 
 void ContactObjectA2PConverter::importPostalList()
 {
+#ifdef FEATURE_EBOOK
+       importList(m_platformContact, *m_abstractContact->getAddresses(),
+                  EVC_ADR, EDSAdrTypes,
+                  &ContactAddress::getTypes,
+                  CopyAddress);
+#else
        int errorCode = 0;
        contacts_record_h child_record = NULL;
        unsigned int record_count = 0;
@@ -1564,10 +1782,14 @@ void ContactObjectA2PConverter::importPostalList()
                        continue;
                }
        }
+#endif
 }
 
 void ContactObjectA2PConverter::importWebAddrList()
 {
+#ifdef FEATURE_EBOOK
+       // TODO as time permits.
+#else
        int errorCode = 0;
        contacts_record_h child_record = NULL;
        unsigned int record_count = 0;
@@ -1666,10 +1888,14 @@ void ContactObjectA2PConverter::importWebAddrList()
                        continue;
                }
        }
+#endif
 }
 
 void ContactObjectA2PConverter::importNicknameList()
 {
+#ifdef FEATURE_EBOOK
+       // Not supported.
+#else
        int errorCode = 0;
        contacts_record_h child_record = NULL;
        unsigned int record_count = 0;
@@ -1738,6 +1964,7 @@ void ContactObjectA2PConverter::importNicknameList()
                        continue;
                }
        }
+#endif
 }
 
 } // Contact
index 279eaa2..8a1fd75 100755 (executable)
@@ -37,8 +37,14 @@ class ContactObjectA2PConverter
 {
 public:
        ContactObjectA2PConverter(const ContactPtr &abstractContact,
-                              bool forScratch);
+#ifdef FEATURE_EBOOK
+                                 EBookClientCXX m_ebook,
+#endif
+                                 bool forScratch);
        ContactObjectA2PConverter(const ContactPtr &abstractContact,
+#ifdef FEATURE_EBOOK
+                                 EBookClientCXX m_ebook,
+#endif
                                  bool forScratch,
                                  contacts_record_h platformContact);
        virtual ~ContactObjectA2PConverter();
@@ -77,6 +83,9 @@ protected:
        void importNicknameList();
 
        ContactPtr m_abstractContact;
+#ifdef FEATURE_EBOOK
+       EBookClientCXX m_ebook;
+#endif
        contacts_record_h                   m_platformContact;
        bool                                m_forScratch;
        bool                                m_convertFinished;
index 9c498ec..6818736 100755 (executable)
@@ -40,8 +40,14 @@ using namespace WrtDeviceApis::Commons;
 using namespace std;
 
 ContactObjectP2AConverter::ContactObjectP2AConverter(contacts_record_h platformContact,
+#ifdef FEATURE_EBOOK
+                                                    EBookClientCXX ebook,
+#endif
                bool forScratch) :
                m_platformContact(platformContact),
+#ifdef FEATURE_EBOOK
+               m_ebook(ebook),
+#endif
                m_abstractContact(ContactPtr(NULL)),
                m_forScratch(forScratch),
                m_convertFinished(false)
@@ -49,9 +55,15 @@ ContactObjectP2AConverter::ContactObjectP2AConverter(contacts_record_h platformC
 }
 
 ContactObjectP2AConverter::ContactObjectP2AConverter(contacts_record_h platformContact,
+#ifdef FEATURE_EBOOK
+                                                    EBookClientCXX ebook,
+#endif
                bool forScratch,
                ContactPtr &abstractContact) :
                m_platformContact(platformContact),
+#ifdef FEATURE_EBOOK
+               m_ebook(ebook),
+#endif
                m_abstractContact(abstractContact),
                m_forScratch(forScratch),
                m_convertFinished(false)
@@ -66,7 +78,7 @@ ContactPtr ContactObjectP2AConverter::getAbstractContact()
 {
        //LoggerD("enter");
 
-       if(m_platformContact == NULL)
+       if(!m_platformContact)
        {
                LoggerE("Platform contact object did not set");
                ThrowMsg(InvalidArgumentException, "Platform contact object did not set");
@@ -113,37 +125,98 @@ void ContactObjectP2AConverter::convertToAbstractObject()
 
 void ContactObjectP2AConverter::exportBaseInfoValue()
 {
+#ifndef FEATURE_EBOOK
        int errorCode = 0;
+#endif
 
        if(!m_forScratch)
        {
+#ifdef FEATURE_EBOOK
+               PlainGStr buffer = EContactFieldCXX<E_CONTACT_UID>::get(m_platformContact);
+               const char *id = buffer;
+#else
                int id = 0;
                contacts_record_get_int(m_platformContact, _contacts_contact.id, &id);
+#endif
                m_abstractContact->setId(id);
 
+#ifdef FEATURE_EBOOK
+               const char *addressBookId;
+               // Conversion might happen without an ebook, in which case we leave this empty.
+               if (m_ebook) {
+                       ESource *source = e_client_get_source(E_CLIENT(m_ebook.get()));
+                       addressBookId = e_source_get_uid(source);
+               } else {
+                       addressBookId = "";
+               }
+               // Compatibility hack with contacts service
+               // implementation: id "0" == "system-address-book".
+               // Not required by API, but might be expected by apps
+               // anyway. Some WRT tests use "0".
+               if (!strcmp(addressBookId, "system-address-book")) {
+                       addressBookId = "0";
+               }
+#else
                int addressBookId = 0;
                contacts_record_get_int(m_platformContact, _contacts_contact.address_book_id, &addressBookId);
+#endif
                m_abstractContact->setAddressBookId(addressBookId);
 
+#ifdef FEATURE_EBOOK
+               // Fake a person ID by reusing the contact
+               // ID. Actually using it will fail, but perhaps having
+               // something set here will help apps which just access
+               // it for debugging purposes.
+               m_abstractContact->setPersonId(id);
+#else
                int personId = 0;
                contacts_record_get_int(m_platformContact, _contacts_contact.person_id, &personId);
                m_abstractContact->setPersonId(personId);
-
+#endif
+
+#ifdef FEATURE_EBOOK
+               PlainGStr rev = EContactFieldCXX<E_CONTACT_REV>::get(m_platformContact);
+               GTimeVal timeval;
+               if (!rev || !rev[0] || !g_time_val_from_iso8601(rev, &timeval)) {
+                       timeval.tv_sec = 0;
+                       timeval.tv_usec = 0;
+               }
+               tm tm;
+               time_t time = timeval.tv_sec;
+               struct tm *changedTimeTm = gmtime_r(&time, &tm);
+#else
                int changedTime = 0;
                contacts_record_get_int(m_platformContact, _contacts_contact.changed_time, &changedTime);
                time_t changedTimeT = static_cast<time_t>(changedTime);
                struct tm *changedTimeTm = gmtime(&changedTimeT);
+#endif
                m_abstractContact->setLastUpdated(*changedTimeTm);
 
+#ifdef FEATURE_EBOOK
+               m_abstractContact->setIsFavorite(false);
+#else
                bool isFavorite = false;
                errorCode = contacts_record_get_bool(m_platformContact, _contacts_contact.is_favorite, &isFavorite);
                if(errorCode != CONTACTS_ERROR_NONE)
                        LoggerE("contacts_record_get_bool returned " << errorCode);
                m_abstractContact->setIsFavorite(isFavorite);
+#endif
        }
 
+#ifndef FEATURE_EBOOK
        char *charValue = NULL;
-
+#endif
+
+#ifdef FEATURE_EBOOK
+       boost::shared_ptr<EContactPhoto> photo = EContactFieldCXX<E_CONTACT_PHOTO>::get(m_platformContact);
+       if (photo &&
+           photo->type == E_CONTACT_PHOTO_TYPE_URI && // EDS always stores as URI, but check anyway.
+           photo->data.uri &&
+           photo->data.uri[0])
+               m_abstractContact->setPhotoURI(photo->data.uri);
+       else
+               m_abstractContact->unsetPhotoURI();
+#else
        contacts_record_get_str_p(m_platformContact, _contacts_contact.image_thumbnail_path, &charValue);
        if (charValue)
                m_abstractContact->setPhotoURI(ContactUtility::convertPathToUri(charValue));
@@ -152,7 +225,11 @@ void ContactObjectP2AConverter::exportBaseInfoValue()
                if(m_abstractContact->getPhotoURIIsSet())
                        m_abstractContact->unsetPhotoURI();
        }
+#endif
 
+#ifdef FEATURE_EBOOK
+       m_abstractContact->unsetRingtoneURI();
+#else
        contacts_record_get_str_p(m_platformContact, _contacts_contact.ringtone_path, &charValue);
        if (charValue)
                m_abstractContact->setRingtoneURI(ContactUtility::convertPathToUri(charValue));
@@ -161,9 +238,24 @@ void ContactObjectP2AConverter::exportBaseInfoValue()
                if(m_abstractContact->getRingtoneURIIsSet())
                        m_abstractContact->unsetRingtoneURI();
        }
+#endif
 
        if(!m_forScratch)
        {
+#ifdef FEATURE_EBOOK
+               PlainGStr buffer = EContactFieldCXX<E_CONTACT_NAME_OR_ORG>::get(m_platformContact);
+               ContactNamePtr contactName = m_abstractContact->getName();
+               const char *displayname = buffer.get();
+               if(contactName == NULL)
+               {
+                       contactName = ContactNamePtr(new ContactName());
+                       m_abstractContact->setName(contactName);
+               }
+               if (displayname)
+                       contactName->setDisplayName(displayname);
+               else
+                       contactName->unsetDisplayName();
+#else
                contacts_record_get_str_p(m_platformContact, _contacts_contact.display_name, &charValue);
                if (charValue)
                {
@@ -177,11 +269,15 @@ void ContactObjectP2AConverter::exportBaseInfoValue()
                }
 //             else
 //                     ThrowMsg(UnknownException, "converting base data (no display name)");
+#endif
        }
 }
 
 void ContactObjectP2AConverter::exportNameValue()
 {
+#ifdef FEATURE_EBOOK
+       boost::shared_ptr<EContactName> name = EContactFieldCXX<E_CONTACT_NAME>::get(m_platformContact);
+#else
        int errorCode = 0;
        contacts_record_h child_record = NULL;
 
@@ -189,7 +285,13 @@ void ContactObjectP2AConverter::exportNameValue()
        if(errorCode != CONTACTS_ERROR_NONE && errorCode != CONTACTS_ERROR_NO_DATA)
                ThrowMsg(UnknownException, "getting name value (err:" << errorCode << ")");
 
+#endif
+
+#ifdef FEATURE_EBOOK
+       if(!name)
+#else
        if(child_record == NULL || errorCode == CONTACTS_ERROR_NO_DATA)
+#endif
        {
                //LoggerD("Platform contact don't have name value");
                ContactNamePtr contactName = m_abstractContact->getName();
@@ -231,7 +333,11 @@ void ContactObjectP2AConverter::exportNameValue()
 
        char *charValue = NULL;
 
+#ifdef FEATURE_EBOOK
+       charValue = name->given;
+#else
        contacts_record_get_str_p(child_record, _contacts_name.first, &charValue);
+#endif
        if (charValue)
                contactName->setFirstName(charValue);
        else
@@ -240,7 +346,11 @@ void ContactObjectP2AConverter::exportNameValue()
                        contactName->unsetFirstName();
        }
 
+#ifdef FEATURE_EBOOK
+       charValue = name->additional;
+#else
        contacts_record_get_str_p(child_record, _contacts_name.addition, &charValue);
+#endif
        if (charValue)
                contactName->setMiddleName(charValue);
        else
@@ -249,7 +359,11 @@ void ContactObjectP2AConverter::exportNameValue()
                        contactName->unsetMiddleName();
        }
 
+#ifdef FEATURE_EBOOK
+       charValue = name->family;
+#else
        contacts_record_get_str_p(child_record, _contacts_name.last, &charValue);
+#endif
        if (charValue)
                contactName->setLastName(charValue);
        else
@@ -258,7 +372,11 @@ void ContactObjectP2AConverter::exportNameValue()
                        contactName->unsetLastName();
        }
 
+#ifdef FEATURE_EBOOK
+       charValue = name->prefixes;
+#else
        contacts_record_get_str_p(child_record, _contacts_name.prefix, &charValue);
+#endif
        if (charValue)
                contactName->setPrefix(charValue);
        else
@@ -267,7 +385,11 @@ void ContactObjectP2AConverter::exportNameValue()
                        contactName->unsetPrefix();
        }
 
+#ifdef FEATURE_EBOOK
+       charValue = name->suffixes;
+#else
        contacts_record_get_str_p(child_record, _contacts_name.suffix, &charValue);
+#endif
        if (charValue)
                contactName->setSuffix(charValue);
        else
@@ -276,7 +398,11 @@ void ContactObjectP2AConverter::exportNameValue()
                        contactName->unsetSuffix();
        }
 
+#ifdef FEATURE_EBOOK
+       charValue = NULL;
+#else
        contacts_record_get_str_p(child_record, _contacts_name.phonetic_first, &charValue);
+#endif
        if (charValue)
                contactName->setPhoneticFirstName(charValue);
        else
@@ -285,7 +411,11 @@ void ContactObjectP2AConverter::exportNameValue()
                        contactName->unsetPhoneticFirstName();
        }
 
+#ifdef FEATURE_EBOOK
+       charValue = NULL;
+#else
        contacts_record_get_str_p(child_record, _contacts_name.phonetic_middle, &charValue);
+#endif
        if (charValue)
                contactName->setPhoneticMiddleName(charValue);
        else
@@ -294,7 +424,11 @@ void ContactObjectP2AConverter::exportNameValue()
                        contactName->unsetPhoneticMiddleName();
        }
 
+#ifdef FEATURE_EBOOK
+       charValue = NULL;
+#else
        contacts_record_get_str_p(child_record, _contacts_name.phonetic_last, &charValue);
+#endif
        if (charValue)
                contactName->setPhoneticLastName(charValue);
        else
@@ -306,12 +440,19 @@ void ContactObjectP2AConverter::exportNameValue()
 
 void ContactObjectP2AConverter::exportCompanyList()
 {
+#ifndef FEATURE_EBOOK
        int errorCode = 0;
        unsigned int child_count = 0;
+#endif
 
        if(m_abstractContact->getOrganizationsNum() > 0)
                m_abstractContact->clearOrganizations();
 
+#ifdef FEATURE_EBOOK
+       // EDS could store multiple ORG properties, but EContact only supports one.
+       // For the sake of simplicity we limit the number of organizations to one
+       // here
+#else
        errorCode = contacts_record_get_child_record_count(m_platformContact, _contacts_contact.company, &child_count);
        if(errorCode != CONTACTS_ERROR_NONE && errorCode != CONTACTS_ERROR_NO_DATA)
                ThrowMsg(UnknownException, "getting company list (err:" << errorCode << ")");
@@ -321,9 +462,11 @@ void ContactObjectP2AConverter::exportCompanyList()
                //LoggerD("Platform contact don't have company list");
                return;
        }
+#endif
 
        ContactOrganizationArrayPtr organizations = m_abstractContact->getOrganizations();
 
+#ifndef FEATURE_EBOOK
        for(unsigned int i=0; i<child_count; i++)
        {
                contacts_record_h child_record = NULL;
@@ -331,13 +474,21 @@ void ContactObjectP2AConverter::exportCompanyList()
                errorCode = contacts_record_get_child_record_at_p(m_platformContact, _contacts_contact.company, i, &child_record);
                if(errorCode != CONTACTS_ERROR_NONE && errorCode != CONTACTS_ERROR_NO_DATA)
                        continue;
+#endif
 
                ContactOrganizationPtr organization(new ContactOrganization());
 
                char *charValue = NULL;
+#ifndef FEATURE_EBOOK
                int intValue = 0;
+#endif
 
+#ifdef FEATURE_EBOOK
+               PlainGStr buffer = EContactFieldCXX<E_CONTACT_ORG>::get(m_platformContact);
+               charValue = buffer;
+#else
                contacts_record_get_str_p(child_record, _contacts_company.name, &charValue);
+#endif
                if (charValue)
                        organization->setName(charValue);
                else
@@ -346,7 +497,12 @@ void ContactObjectP2AConverter::exportCompanyList()
                                organization->unsetName();
                }
 
+#ifdef FEATURE_EBOOK
+               buffer = EContactFieldCXX<E_CONTACT_ORG_UNIT>::get(m_platformContact);
+               charValue = buffer;
+#else
                contacts_record_get_str_p(child_record, _contacts_company.department, &charValue);
+#endif
                if (charValue)
                        organization->setDepartment(charValue);
                else
@@ -355,7 +511,12 @@ void ContactObjectP2AConverter::exportCompanyList()
                                organization->unsetDepartment();
                }
 
+#ifdef FEATURE_EBOOK
+               buffer = EContactFieldCXX<E_CONTACT_TITLE>::get(m_platformContact);
+               charValue = buffer;
+#else
                contacts_record_get_str_p(child_record, _contacts_company.job_title, &charValue);
+#endif
                if (charValue)
                        organization->setTitle(charValue);
                else
@@ -364,7 +525,12 @@ void ContactObjectP2AConverter::exportCompanyList()
                                organization->unsetTitle();
                }
 
+#ifdef FEATURE_EBOOK
+               buffer = EContactFieldCXX<E_CONTACT_ROLE>::get(m_platformContact);
+               charValue = buffer;
+#else
                contacts_record_get_str_p(child_record, _contacts_company.role, &charValue);
+#endif
                if (charValue)
                        organization->setRole(charValue);
                else
@@ -373,7 +539,11 @@ void ContactObjectP2AConverter::exportCompanyList()
                                organization->unsetRole();
                }
 
+#ifdef FEATURE_EBOOK
+               charValue = NULL;
+#else
                contacts_record_get_str_p(child_record, _contacts_company.logo, &charValue);
+#endif
                if (charValue)
                        organization->setLogoURI(ContactUtility::convertPathToUri(charValue));
                else
@@ -382,7 +552,12 @@ void ContactObjectP2AConverter::exportCompanyList()
                                organization->unsetLogoURI();
                }
 
+#ifdef FEATURE_EBOOK
+               buffer = EContactFieldCXX<E_CONTACT_ASSISTANT>::get(m_platformContact);
+               charValue = buffer;
+#else
                contacts_record_get_str_p(child_record, _contacts_company.assistant_name, &charValue);
+#endif
                if (charValue)
                        organization->setAssistant(charValue);
                else
@@ -391,7 +566,11 @@ void ContactObjectP2AConverter::exportCompanyList()
                                organization->unsetAssistant();
                }
 
+#ifdef FEATURE_EBOOK
+               charValue = NULL;
+#else
                contacts_record_get_str_p(child_record, _contacts_company.location, &charValue);
+#endif
                if (charValue)
                        organization->setLocation(charValue);
                else
@@ -400,7 +579,11 @@ void ContactObjectP2AConverter::exportCompanyList()
                                organization->unsetLocation();
                }
 
+#ifdef FEATURE_EBOOK
+               charValue = NULL;
+#else
                contacts_record_get_str_p(child_record, _contacts_company.description, &charValue);
+#endif
                if (charValue)
                        organization->setDescription(charValue);
                else
@@ -409,7 +592,11 @@ void ContactObjectP2AConverter::exportCompanyList()
                                organization->unsetDescription();
                }
 
+#ifdef FEATURE_EBOOK
+               charValue = NULL;
+#else
                contacts_record_get_str_p(child_record, _contacts_company.phonetic_name, &charValue);
+#endif
                if (charValue)
                        organization->setPhoneticName(charValue);
                else
@@ -418,16 +605,23 @@ void ContactObjectP2AConverter::exportCompanyList()
                                organization->unsetPhoneticName();
                }
 
+#ifndef FEATURE_EBOOK
                contacts_record_get_int(child_record, _contacts_company.type, &intValue);
                if(intValue == CONTACTS_COMPANY_TYPE_OTHER)
                        organization->setType(ORGANIZATION_TYPE_OTHER);
                if(intValue == CONTACTS_COMPANY_TYPE_WORK)
                        organization->setType(ORGANIZATION_TYPE_WORK);
+#endif
 
                if(organization->getTypeIsSet() == false)
                        organization->setType(ORGANIZATION_TYPE_WORK);
 
+
+#ifdef FEATURE_EBOOK
+               charValue = NULL;
+#else
                contacts_record_get_str_p(child_record, _contacts_company.label, &charValue);
+#endif
                if (charValue)
                        organization->setLabel(charValue);
                else
@@ -437,17 +631,24 @@ void ContactObjectP2AConverter::exportCompanyList()
                }
                organizations->push_back(organization);
 
+#ifndef FEATURE_EBOOK
        }
+#endif
 }
 
 void ContactObjectP2AConverter::exportNoteList()
 {
+#ifndef FEATURE_EBOOK
        int errorCode = 0;
        unsigned int child_count = 0;
+#endif
 
        if(m_abstractContact->getNotesNum() > 0)
                m_abstractContact->clearNotes();
 
+#ifdef FEATURE_EBOOK
+       // Same as ORG - only one NOTE supported.
+#else
        errorCode = contacts_record_get_child_record_count(m_platformContact, _contacts_contact.note, &child_count);
        if(errorCode != CONTACTS_ERROR_NONE && errorCode != CONTACTS_ERROR_NO_DATA)
                ThrowMsg(UnknownException, "getting note list (err:" << errorCode << ")");
@@ -457,9 +658,11 @@ void ContactObjectP2AConverter::exportNoteList()
                //LoggerD("Platform contact don't have note list");
                return;
        }
+#endif
 
        StringArrayPtr notes = m_abstractContact->getNotes();
 
+#ifndef FEATURE_EBOOK
        for(unsigned int i=0; i<child_count; i++)
        {
                contacts_record_h child_record = NULL;
@@ -467,17 +670,160 @@ void ContactObjectP2AConverter::exportNoteList()
                errorCode = contacts_record_get_child_record_at_p(m_platformContact, _contacts_contact.note, i, &child_record);
                if(errorCode != CONTACTS_ERROR_NONE && errorCode != CONTACTS_ERROR_NO_DATA)
                        continue;
+#endif
 
                char *charValue = NULL;
 
+#ifdef FEATURE_EBOOK
+               PlainGStr buffer = EContactFieldCXX<E_CONTACT_NOTE>::get(m_platformContact);
+               charValue = buffer;
+#else
                contacts_record_get_str_p(child_record, _contacts_note.note, &charValue);
+#endif
                if (charValue)
                        notes->push_back(charValue);
+#ifndef FEATURE_EBOOK
        }
+#endif
 }
 
+#ifdef FEATURE_EBOOK
+static bool IsType(EVCardAttributeParam *param, const char *type)
+{
+       // match shortcut when type is given without TYPE=
+       const char *name = e_vcard_attribute_param_get_name(param);
+       if (!strcasecmp(name, type))
+               return true;
+
+       // TYPE parameter?
+       if (strcasecmp(name, "TYPE"))
+               return false;
+
+       // Check each value of TYPE.
+       GListCXX<char, GList, NoopDestructor<char>, false> values(e_vcard_attribute_param_get_values(param));
+       BOOST_FOREACH (const char *value, values) {
+               if (!strcasecmp(value, type))
+                       return true;
+       }
+
+       return false;
+}
+
+
+
+// Implements both exportNumberList and exportEmailList.
+template<class E, class EArray, class T, class V, class AT, class GT>
+void exportList(contacts_record_h &record, Contact *contact,
+               const char *property,
+               const Types<T> *types,
+               T defType,
+               V *(*getValue)(EVCardAttribute *),
+               void (Contact::*clearList)(),
+               EArray (IContact::*getList)() const,
+               const boost::function<void (E &, V *)> set,
+               // Can't be more specific here because
+               // ContactAddress::addType is not consistent with
+               // other addType calls (it uses const, the other's dont).
+               AT addType, // void (E::*addType)(T),
+               GT (E::*getTypes)() const
+               )
+{
+       (contact->*clearList)();
+
+       // workaround for g++/linker issue: method not included in .so unless
+       // we call it explicitly here.
+       NoopDestructor<EVCardAttribute>(NULL);
+       GListCXX<EVCardAttribute, GList, NoopDestructor<EVCardAttribute>, false> attributes(e_vcard_get_attributes(E_VCARD(record.get())));
+       EArray entries = (contact->*getList)();
+
+       BOOST_FOREACH (EVCardAttribute *attribute, attributes)
+       {
+               const char *name = e_vcard_attribute_get_name(attribute);
+               if (!name || strcasecmp(name, property))
+                       continue;
+
+               DPL::SharedPtr<E> entry(new E());
+
+               V *value = getValue(attribute);
+               if (value)
+               {
+                       set(*entry, value);
+               }
+               else
+               {
+                       //LoggerD("Platform contact have a empty phone number");
+                       continue;
+               }
+
+               // Same workaround as for GListCXX<EVCardAttribute...
+               NoopDestructor<EVCardAttributeParam>(NULL);
+               GListCXX<EVCardAttributeParam, GList, NoopDestructor<EVCardAttributeParam>, false> params(e_vcard_attribute_get_params(attribute));
+               BOOST_FOREACH (EVCardAttributeParam *param, params) {
+                       for (const Types<T> *type = types;
+                            type->typeString;
+                            type++) {
+                               if (IsType(param, type->typeString))
+                                       ((*entry).*addType)(type->enumVal);
+                       }
+               }
+
+               if(((*entry).*getTypes)()->size() == 0)
+                       ((*entry).*addType)(defType);
+
+               entries->push_back(entry);
+       }
+}
+
+Types<ContactPhoneNumberType> EDSTelTypes[] = {
+       { "HOME", CONTACT_PHONE_NUMBER_TYPE_HOME },
+       { "WORK", CONTACT_PHONE_NUMBER_TYPE_WORK },
+       { "VOICE", CONTACT_PHONE_NUMBER_TYPE_VOICE },
+       { "FAX", CONTACT_PHONE_NUMBER_TYPE_FAX },
+       { "MSG", CONTACT_PHONE_NUMBER_TYPE_MSG },
+       { "CELL", CONTACT_PHONE_NUMBER_TYPE_CELL },
+       { "PAGER", CONTACT_PHONE_NUMBER_TYPE_PAGER },
+       { "BBS", CONTACT_PHONE_NUMBER_TYPE_BBS },
+       { "MODEM", CONTACT_PHONE_NUMBER_TYPE_MODEM },
+       { "CAR", CONTACT_PHONE_NUMBER_TYPE_CAR },
+       { "ISDN", CONTACT_PHONE_NUMBER_TYPE_ISDN },
+       { "VIDEO", CONTACT_PHONE_NUMBER_TYPE_VIDEO },
+       { "PCS", CONTACT_PHONE_NUMBER_TYPE_PCS },
+       { "X-EVOLUTION-ASSISTANT", CONTACT_PHONE_NUMBER_TYPE_ASSISTANT },
+       { "X-ASSISTANT", CONTACT_PHONE_NUMBER_TYPE_ASSISTANT },
+       { "ASSISTANT", CONTACT_PHONE_NUMBER_TYPE_ASSISTANT },
+       { NULL }
+};
+
+Types<ContactEmailAddressType> EDSEmailTypes[] = {
+       { "HOME", CONTACT_EMAIL_TYPE_HOME },
+       { "WORK", CONTACT_EMAIL_TYPE_WORK },
+       { "MOBILE", CONTACT_EMAIL_TYPE_MOBILE },
+       { NULL }
+};
+
+Types<ContactAddressType> EDSAdrTypes[] = {
+       { "HOME", CONTACT_ADDRESS_TYPE_HOME },
+       { "WORK", CONTACT_ADDRESS_TYPE_WORK },
+       { "DOM", CONTACT_ADDRESS_TYPE_DOM },
+       { "INTL", CONTACT_ADDRESS_TYPE_INTL },
+       { "POSTAL", CONTACT_ADDRESS_TYPE_POSTAL },
+       { "PARCEL", CONTACT_ADDRESS_TYPE_PARCEL },
+       { NULL }
+};
+#endif // FEATURE_EBOOK
+
 void ContactObjectP2AConverter::exportNumberList()
 {
+#ifdef FEATURE_EBOOK
+       exportList(m_platformContact, &*DPL::StaticPointerCast<Contact>(m_abstractContact),
+                  EVC_TEL, EDSTelTypes, CONTACT_PHONE_NUMBER_TYPE_VOICE,
+                  e_vcard_attribute_get_value,
+                  &Contact::resetNumbersJSObj,
+                  &Contact::getPhoneNumbers,
+                  boost::function<void (ContactPhoneNumber &, char *)>(boost::bind(&ContactPhoneNumber::setNumber, _1, _2)),
+                  &ContactPhoneNumber::addType,
+                  &ContactPhoneNumber::getTypes);
+#else
        int errorCode = 0;
        unsigned int child_count = 0;
 
@@ -566,10 +912,21 @@ void ContactObjectP2AConverter::exportNumberList()
 
                phoneNumbers->push_back(phoneNumber);
        }
+#endif
 }
 
 void ContactObjectP2AConverter::exportEmailList()
 {
+#ifdef FEATURE_EBOOK
+       exportList(m_platformContact, &*DPL::StaticPointerCast<Contact>(m_abstractContact),
+                  EVC_EMAIL, EDSEmailTypes, CONTACT_EMAIL_TYPE_WORK,
+                  e_vcard_attribute_get_value,
+                  &Contact::resetEmailsJSObj,
+                  &Contact::getEmails,
+                  boost::function<void (ContactEmailAddress &, char *)>(boost::bind(&ContactEmailAddress::setEmail, _1, _2)),
+                  &ContactEmailAddress::addType,
+                  &ContactEmailAddress::getTypes);
+#else
        int errorCode = 0;
        unsigned int child_count = 0;
 
@@ -639,10 +996,15 @@ void ContactObjectP2AConverter::exportEmailList()
 
                emails->push_back(email);
        }
+#endif
 }
 
 void ContactObjectP2AConverter::exportGrouprelList()
 {
+#ifdef FEATURE_EBOOK
+       // Not supported.
+       m_abstractContact->clearGroupIds();
+#else
        int errorCode = 0;
        unsigned int child_count = 0;
 
@@ -675,10 +1037,27 @@ void ContactObjectP2AConverter::exportGrouprelList()
 
                groupIds->push_back(ContactUtility::intToStr(groupId));
        }
+#endif
 }
 
 void ContactObjectP2AConverter::exportEventList()
 {
+#ifdef FEATURE_EBOOK
+       // Generic list of anniversaries not supported by the
+       // mapping. EDS has one anniversary field, we could use that.
+       m_abstractContact->clearAnniversaries();
+
+       boost::shared_ptr<EContactDate> bday = EContactFieldCXX<E_CONTACT_BIRTH_DATE>::get(m_platformContact);
+       if (bday) {
+               tm tmDate = {0, };
+               tmDate.tm_year = bday->year;
+               tmDate.tm_mon = bday->month;
+               tmDate.tm_mday = bday->day;
+               m_abstractContact->setBirthday(tmDate);
+       } else {
+               m_abstractContact->unsetBirthday();
+       }
+#else
        int errorCode = 0;
        unsigned int child_count = 0;
 
@@ -748,10 +1127,65 @@ void ContactObjectP2AConverter::exportEventList()
                        anniversaries->push_back(anniversary);
                }
        }
+#endif
+}
+
+#ifdef FEATURE_EBOOK
+const char *getComponent(GList *&values)
+{
+       if (values) {
+               const char *res = static_cast<const char *>(values->data);
+               values = values->next;
+               return res;
+       } else {
+               return NULL;
+       }
+}
+
+static void SetAddress(ContactAddress &address, GList *values)
+{
+       // Treating empty strings as "unset" follows the behavior of
+       // the rest of the code. vCard itself cannot distinguish
+       // well between unset and empty components, because the initial
+       // components must be set if one of the following ones is.
+       const char *charValue = getComponent(values);
+       if (charValue && charValue[0])
+               address.setPostalCode(charValue);
+
+       charValue = getComponent(values);
+       if (charValue && charValue[0])
+               address.setRegion(charValue);
+
+       charValue = getComponent(values);
+       if (charValue && charValue[0])
+               address.setCity(charValue);
+
+       charValue = getComponent(values);
+       if (charValue && charValue[0])
+               address.setStreetAddress(charValue);
+
+       charValue = getComponent(values);
+       if (charValue && charValue[0])
+               address.setAdditionalInformation(charValue);
+
+       charValue = getComponent(values);
+       if (charValue && charValue[0])
+               address.setCountry(charValue);
 }
+#endif
 
 void ContactObjectP2AConverter::exportPostalList()
 {
+#ifdef FEATURE_EBOOK
+       exportList(m_platformContact, &*DPL::StaticPointerCast<Contact>(m_abstractContact),
+                  EVC_ADR, EDSAdrTypes, CONTACT_ADDRESS_TYPE_HOME,
+                  e_vcard_attribute_get_values,
+                  &Contact::resetAddressesJSObj,
+                  &Contact::getAddresses,
+                  boost::function<void (ContactAddress &, GList *)>(boost::bind(SetAddress, _1, _2)),
+                  &ContactAddress::addType,
+                  &ContactAddress::getTypes);
+#else
        int errorCode = 0;
        unsigned int child_count = 0;
 
@@ -837,10 +1271,14 @@ void ContactObjectP2AConverter::exportPostalList()
 
                addresses->push_back(address);
        }
+#endif
 }
 
 void ContactObjectP2AConverter::exportWebAddrList()
 {
+#ifdef FEATURE_EBOOK
+       // TODO as time permits.
+#else
        int errorCode = 0;
        unsigned int child_count = 0;
 
@@ -891,12 +1329,15 @@ void ContactObjectP2AConverter::exportWebAddrList()
 
                urls->push_back(url);
        }
+#endif
 }
 
 void ContactObjectP2AConverter::exportNicknameList()
 {
+#ifndef FEATURE_EBOOK
        int errorCode = 0;
        unsigned int child_count = 0;
+#endif
 
        ContactNamePtr contactName = m_abstractContact->getName();
        if(contactName == NULL)
@@ -908,6 +1349,10 @@ void ContactObjectP2AConverter::exportNicknameList()
        if(contactName->getNicknamesNum() > 0)
                contactName->clearNicknames();
 
+#ifdef FEATURE_EBOOK
+       // Not supported.
+       return;
+#else
        errorCode = contacts_record_get_child_record_count(m_platformContact, _contacts_contact.nickname, &child_count);
        if(errorCode != CONTACTS_ERROR_NONE && errorCode != CONTACTS_ERROR_NO_DATA)
                ThrowMsg(UnknownException, "getting nickname list (err:" << errorCode << ")");
@@ -934,6 +1379,7 @@ void ContactObjectP2AConverter::exportNicknameList()
                if (charValue)
                        nicknames->push_back(charValue);
        }
+#endif
 }
 
 } // Contact
index ffb3f2f..f4f894b 100755 (executable)
 namespace DeviceAPI {
 namespace Contact {
 
+#ifdef FEATURE_EBOOK
+template<class T> struct Types { const char *typeString; T enumVal; };
+extern Types<ContactPhoneNumberType> EDSTelTypes[];
+extern Types<ContactEmailAddressType> EDSEmailTypes[];
+extern Types<ContactAddressType> EDSAdrTypes[];
+#endif
+
 class ContactObjectP2AConverter
 {
 public:
        ContactObjectP2AConverter(contacts_record_h platformContact,
+#ifdef FEATURE_EBOOK
+                                 EBookClientCXX m_ebook,
+#endif
                                  bool forScratch);
        ContactObjectP2AConverter(contacts_record_h platformContact,
+#ifdef FEATURE_EBOOK
+                                 EBookClientCXX m_ebook,
+#endif
                                  bool forScratch,
                                  ContactPtr &abstractContact);
        virtual ~ContactObjectP2AConverter();
@@ -61,6 +74,9 @@ protected:
        void exportNicknameList();
 
        contacts_record_h                   m_platformContact;
+#ifdef FEATURE_EBOOK
+       EBookClientCXX m_ebook;
+#endif
        ContactPtr m_abstractContact;
        bool                                m_forScratch;
        bool                                m_convertFinished;
index 23bb9f2..3e02366 100755 (executable)
 #include "ContactUtility.h"
 #include <Logger.h>
 
+#ifdef FEATURE_EBOOK
+# include <boost/scoped_array.hpp>
+#endif
+
 #define _CONTACTS_SVC_QUERY_FUNC_PREFIX(view_uri, query, filter) \
        do { \
                if((errorCode = contacts_query_create(view_uri, &query)) != CONTACTS_ERROR_NONE) \
@@ -79,58 +83,77 @@ using namespace WrtDeviceApis::Commons;
 using namespace DeviceAPI::Tizen;
 using namespace std;
 
+// Picks first two parameters when using contacts service, otherwise the last two.
+// Use NULL, E_CONTACT_FIELD_LAST for EDS vCardField/contactField when searching
+// is not supported in EDS for that attribute.
+#ifdef FEATURE_EBOOK
+# define IF_SVC_ELSE(_viewUri, _propertyContactId, _propertyId, _vCardField, _contactField) _vCardField, _contactField
+#else
+# define IF_SVC_ELSE(_viewUri, _propertyContactId, _propertyId, _vCardField, _contactField) _viewUri, _propertyContactId, _propertyId
+#endif
+
+
 ContactSearchEngine::AttributePropertiesMap ContactSearchEngine::attributePropertiesMap = {
-               {"id",                      { _contacts_simple_contact._uri, _contacts_simple_contact.id, _contacts_simple_contact.id, ContactSearchEngine::ContactSvcPrimitiveType_Int, PrimitiveType_String } },
-               {"personId",                { _contacts_simple_contact._uri, _contacts_simple_contact.id, _contacts_simple_contact.person_id, ContactSearchEngine::ContactSvcPrimitiveType_Int, PrimitiveType_String } },
-               {"addressBookId",           { _contacts_simple_contact._uri, _contacts_simple_contact.id, _contacts_simple_contact.address_book_id, ContactSearchEngine::ContactSvcPrimitiveType_Int, PrimitiveType_String } },
-               {"lastUpdated",             { _contacts_simple_contact._uri, _contacts_simple_contact.id, _contacts_simple_contact.changed_time, ContactSearchEngine::ContactSvcPrimitiveType_Int, PrimitiveType_Time } },
-               {"isFavorite",              { _contacts_simple_contact._uri, _contacts_simple_contact.id, _contacts_simple_contact.is_favorite, ContactSearchEngine::ContactSvcPrimitiveType_Boolean, PrimitiveType_Boolean } },
-               {"name.prefix",             { _contacts_name._uri, _contacts_name.contact_id, _contacts_name.prefix, ContactSearchEngine::ContactSvcPrimitiveType_String, PrimitiveType_String } },
-               {"name.suffix",             { _contacts_name._uri, _contacts_name.contact_id, _contacts_name.suffix, ContactSearchEngine::ContactSvcPrimitiveType_String, PrimitiveType_String } },
-               {"name.firstName",          { _contacts_name._uri, _contacts_name.contact_id, _contacts_name.first, ContactSearchEngine::ContactSvcPrimitiveType_String, PrimitiveType_String } },
-               {"name.middleName",         { _contacts_name._uri, _contacts_name.contact_id, _contacts_name.addition, ContactSearchEngine::ContactSvcPrimitiveType_String, PrimitiveType_String } },
-               {"name.lastName",           { _contacts_name._uri, _contacts_name.contact_id, _contacts_name.last, ContactSearchEngine::ContactSvcPrimitiveType_String, PrimitiveType_String } },
-               {"name.nicknames",          { _contacts_nickname._uri, _contacts_nickname.contact_id, _contacts_nickname.name, ContactSearchEngine::ContactSvcPrimitiveType_String, PrimitiveType_String } },
-               {"name.phoneticFirstName",  { _contacts_name._uri, _contacts_name.contact_id, _contacts_name.phonetic_first, ContactSearchEngine::ContactSvcPrimitiveType_String, PrimitiveType_String } },
-               {"name.phoneticMiddleName",  { _contacts_name._uri, _contacts_name.contact_id, _contacts_name.phonetic_middle, ContactSearchEngine::ContactSvcPrimitiveType_String, PrimitiveType_String } },
-               {"name.phoneticLastName",   { _contacts_name._uri, _contacts_name.contact_id, _contacts_name.phonetic_last, ContactSearchEngine::ContactSvcPrimitiveType_String, PrimitiveType_String } },
-               {"name.displayName",        { _contacts_simple_contact._uri, _contacts_simple_contact.id, _contacts_simple_contact.display_name, ContactSearchEngine::ContactSvcPrimitiveType_String, PrimitiveType_String } },
-               {"addresses.country",       { _contacts_address._uri, _contacts_address.contact_id, _contacts_address.country, ContactSearchEngine::ContactSvcPrimitiveType_String, PrimitiveType_String } },
-               {"addresses.region",        { _contacts_address._uri, _contacts_address.contact_id, _contacts_address.region, ContactSearchEngine::ContactSvcPrimitiveType_String, PrimitiveType_String } },
-               {"addresses.city",          { _contacts_address._uri, _contacts_address.contact_id, _contacts_address.locality, ContactSearchEngine::ContactSvcPrimitiveType_String, PrimitiveType_String } },
-               {"addresses.streetAddress", { _contacts_address._uri, _contacts_address.contact_id, _contacts_address.street, ContactSearchEngine::ContactSvcPrimitiveType_String, PrimitiveType_String } },
-               {"addresses.additionalInformation", { _contacts_address._uri, _contacts_address.contact_id, _contacts_address.extended, ContactSearchEngine::ContactSvcPrimitiveType_String, PrimitiveType_String } },
-               {"addresses.postalCode",    { _contacts_address._uri, _contacts_address.contact_id, _contacts_address.postal_code, ContactSearchEngine::ContactSvcPrimitiveType_String, PrimitiveType_String } },
-               {"addresses.isDefault",     { _contacts_address._uri, _contacts_address.contact_id, _contacts_address.is_default, ContactSearchEngine::ContactSvcPrimitiveType_Boolean, PrimitiveType_Boolean } },
-               {"addresses.types",         { _contacts_address._uri, _contacts_address.contact_id, _contacts_address.type, ContactSearchEngine::ContactSvcPrimitiveType_Int, PrimitiveType_Long } },
-               {"photoURI",                { _contacts_simple_contact._uri, _contacts_simple_contact.id, _contacts_simple_contact.image_thumbnail_path, ContactSearchEngine::ContactSvcPrimitiveType_String, PrimitiveType_String } },
-               {"phoneNumbers.number",     { _contacts_number._uri, _contacts_number.contact_id, _contacts_number.number, ContactSearchEngine::ContactSvcPrimitiveType_String, PrimitiveType_String } },
-               {"phoneNumbers.isDefault",  { _contacts_number._uri, _contacts_number.contact_id, _contacts_number.is_default, ContactSearchEngine::ContactSvcPrimitiveType_Boolean, PrimitiveType_Boolean } },
-               {"phoneNumbers.types",      { _contacts_number._uri, _contacts_number.contact_id, _contacts_number.type, ContactSearchEngine::ContactSvcPrimitiveType_Int, PrimitiveType_Long } },
-               {"emails.email",            { _contacts_email._uri, _contacts_email.contact_id, _contacts_email.email, ContactSearchEngine::ContactSvcPrimitiveType_String, PrimitiveType_String } },
-               {"emails.isDefault",        { _contacts_email._uri, _contacts_email.contact_id, _contacts_email.is_default, ContactSearchEngine::ContactSvcPrimitiveType_Boolean, PrimitiveType_Boolean } },
-               {"emails.types",            { _contacts_email._uri, _contacts_email.contact_id, _contacts_email.type, ContactSearchEngine::ContactSvcPrimitiveType_Int, PrimitiveType_Long } },
-               {"birthday",                { _contacts_event._uri, _contacts_event.contact_id, _contacts_event.date, ContactSearchEngine::ContactSvcPrimitiveType_Int, PrimitiveType_Long } },
-               {"anniversaries.date",      { _contacts_event._uri, _contacts_event.contact_id, _contacts_event.date, ContactSearchEngine::ContactSvcPrimitiveType_Int, PrimitiveType_Long } },
-               {"anniversaries.label",     { _contacts_event._uri, _contacts_event.contact_id, _contacts_event.label, ContactSearchEngine::ContactSvcPrimitiveType_String, PrimitiveType_String } },
-               {"organizations.name",      { _contacts_company._uri, _contacts_company.contact_id, _contacts_company.name, ContactSearchEngine::ContactSvcPrimitiveType_String, PrimitiveType_String } },
-               {"organizations.department",{ _contacts_company._uri, _contacts_company.contact_id, _contacts_company.department, ContactSearchEngine::ContactSvcPrimitiveType_String, PrimitiveType_String } },
-               {"organizations.title",     { _contacts_company._uri, _contacts_company.contact_id, _contacts_company.job_title, ContactSearchEngine::ContactSvcPrimitiveType_String, PrimitiveType_String } },
-               {"organizations.role",      { _contacts_company._uri, _contacts_company.contact_id, _contacts_company.role, ContactSearchEngine::ContactSvcPrimitiveType_String, PrimitiveType_String } },
-               {"organizations.logoURI",   { _contacts_company._uri, _contacts_company.contact_id, _contacts_company.logo, ContactSearchEngine::ContactSvcPrimitiveType_String, PrimitiveType_String } },
-               {"organizations.assistant", { _contacts_company._uri, _contacts_company.contact_id, _contacts_company.assistant_name, ContactSearchEngine::ContactSvcPrimitiveType_String, PrimitiveType_String } },
-               {"organizations.location",  { _contacts_company._uri, _contacts_company.contact_id, _contacts_company.location, ContactSearchEngine::ContactSvcPrimitiveType_String, PrimitiveType_String } },
-               {"organizations.description",  { _contacts_company._uri, _contacts_company.contact_id, _contacts_company.description, ContactSearchEngine::ContactSvcPrimitiveType_String, PrimitiveType_String } },
-               {"organizations.phoneticName", { _contacts_company._uri, _contacts_company.contact_id, _contacts_company.phonetic_name, ContactSearchEngine::ContactSvcPrimitiveType_String, PrimitiveType_String } },
-               {"organizations.type",      { _contacts_company._uri, _contacts_company.contact_id, _contacts_company.type, ContactSearchEngine::ContactSvcPrimitiveType_String, PrimitiveType_Long } },
-               {"notes",                   { _contacts_note._uri, _contacts_note.contact_id, _contacts_note.note, ContactSearchEngine::ContactSvcPrimitiveType_String, PrimitiveType_String } },
-               {"urls.url",                { _contacts_url._uri, _contacts_url.contact_id, _contacts_url.url, ContactSearchEngine::ContactSvcPrimitiveType_String, PrimitiveType_String } },
-               {"urls.type",               { _contacts_url._uri, _contacts_url.contact_id, _contacts_url.type, ContactSearchEngine::ContactSvcPrimitiveType_Int, PrimitiveType_Long } },
-               {"ringtoneURI",             { _contacts_simple_contact._uri, _contacts_simple_contact.id, _contacts_simple_contact.ringtone_path, ContactSearchEngine::ContactSvcPrimitiveType_String, PrimitiveType_String } },
-               {"groupIds",                { _contacts_group_relation._uri, _contacts_group_relation.contact_id, _contacts_group_relation.group_id, ContactSearchEngine::ContactSvcPrimitiveType_Int, PrimitiveType_Long } }
+
+               {"id",                      { IF_SVC_ELSE(_contacts_simple_contact._uri, _contacts_simple_contact.id, _contacts_simple_contact.id, NULL, E_CONTACT_UID), ContactSearchEngine::ContactSvcPrimitiveType_Int, PrimitiveType_String } },
+               {"personId",                { IF_SVC_ELSE(_contacts_simple_contact._uri, _contacts_simple_contact.id, _contacts_simple_contact.person_id, NULL, E_CONTACT_FIELD_LAST), ContactSearchEngine::ContactSvcPrimitiveType_Int, PrimitiveType_String } },
+               {"addressBookId",           { IF_SVC_ELSE(_contacts_simple_contact._uri, _contacts_simple_contact.id, _contacts_simple_contact.address_book_id, NULL, E_CONTACT_FIELD_LAST), ContactSearchEngine::ContactSvcPrimitiveType_Int, PrimitiveType_String } },
+               {"lastUpdated",             { IF_SVC_ELSE(_contacts_simple_contact._uri, _contacts_simple_contact.id, _contacts_simple_contact.changed_time, NULL, E_CONTACT_REV), ContactSearchEngine::ContactSvcPrimitiveType_Int, PrimitiveType_Time } },
+               {"isFavorite",              { IF_SVC_ELSE(_contacts_simple_contact._uri, _contacts_simple_contact.id, _contacts_simple_contact.is_favorite, NULL, E_CONTACT_FIELD_LAST), ContactSearchEngine::ContactSvcPrimitiveType_Boolean, PrimitiveType_Boolean } },
+               {"name.prefix",             { IF_SVC_ELSE(_contacts_name._uri, _contacts_name.contact_id, _contacts_name.prefix, NULL, E_CONTACT_FIELD_LAST), ContactSearchEngine::ContactSvcPrimitiveType_String, PrimitiveType_String } },
+               {"name.suffix",             { IF_SVC_ELSE(_contacts_name._uri, _contacts_name.contact_id, _contacts_name.suffix, NULL, E_CONTACT_FIELD_LAST), ContactSearchEngine::ContactSvcPrimitiveType_String, PrimitiveType_String } },
+               {"name.firstName",          { IF_SVC_ELSE(_contacts_name._uri, _contacts_name.contact_id, _contacts_name.first, NULL, E_CONTACT_GIVEN_NAME), ContactSearchEngine::ContactSvcPrimitiveType_String, PrimitiveType_String } },
+               {"name.middleName",         { IF_SVC_ELSE(_contacts_name._uri, _contacts_name.contact_id, _contacts_name.addition, NULL, E_CONTACT_FIELD_LAST), ContactSearchEngine::ContactSvcPrimitiveType_String, PrimitiveType_String } },
+               {"name.lastName",           { IF_SVC_ELSE(_contacts_name._uri, _contacts_name.contact_id, _contacts_name.last, NULL, E_CONTACT_FAMILY_NAME), ContactSearchEngine::ContactSvcPrimitiveType_String, PrimitiveType_String } },
+               {"name.nicknames",          { IF_SVC_ELSE(_contacts_nickname._uri, _contacts_nickname.contact_id, _contacts_nickname.name, NULL, E_CONTACT_NICKNAME), ContactSearchEngine::ContactSvcPrimitiveType_String, PrimitiveType_String } },
+               {"name.phoneticFirstName",  { IF_SVC_ELSE(_contacts_name._uri, _contacts_name.contact_id, _contacts_name.phonetic_first, NULL, E_CONTACT_FIELD_LAST), ContactSearchEngine::ContactSvcPrimitiveType_String, PrimitiveType_String } },
+               {"name.phoneticMiddleName",  { IF_SVC_ELSE(_contacts_name._uri, _contacts_name.contact_id, _contacts_name.phonetic_middle, NULL, E_CONTACT_FIELD_LAST), ContactSearchEngine::ContactSvcPrimitiveType_String, PrimitiveType_String } },
+               {"name.phoneticLastName",   { IF_SVC_ELSE(_contacts_name._uri, _contacts_name.contact_id, _contacts_name.phonetic_last, NULL, E_CONTACT_FIELD_LAST), ContactSearchEngine::ContactSvcPrimitiveType_String, PrimitiveType_String } },
+               {"name.displayName",        { IF_SVC_ELSE(_contacts_simple_contact._uri, _contacts_simple_contact.id, _contacts_simple_contact.display_name, NULL, E_CONTACT_NAME_OR_ORG), ContactSearchEngine::ContactSvcPrimitiveType_String, PrimitiveType_String } },
+               {"addresses.country",       { IF_SVC_ELSE(_contacts_address._uri, _contacts_address.contact_id, _contacts_address.country, NULL, E_CONTACT_FIELD_LAST), ContactSearchEngine::ContactSvcPrimitiveType_String, PrimitiveType_String } },
+               {"addresses.region",        { IF_SVC_ELSE(_contacts_address._uri, _contacts_address.contact_id, _contacts_address.region, NULL, E_CONTACT_FIELD_LAST), ContactSearchEngine::ContactSvcPrimitiveType_String, PrimitiveType_String } },
+               {"addresses.city",          { IF_SVC_ELSE(_contacts_address._uri, _contacts_address.contact_id, _contacts_address.locality, NULL, E_CONTACT_FIELD_LAST), ContactSearchEngine::ContactSvcPrimitiveType_String, PrimitiveType_String } },
+               {"addresses.streetAddress", { IF_SVC_ELSE(_contacts_address._uri, _contacts_address.contact_id, _contacts_address.street, NULL, E_CONTACT_FIELD_LAST), ContactSearchEngine::ContactSvcPrimitiveType_String, PrimitiveType_String } },
+               {"addresses.additionalInformation", { IF_SVC_ELSE(_contacts_address._uri, _contacts_address.contact_id, _contacts_address.extended, NULL, E_CONTACT_FIELD_LAST), ContactSearchEngine::ContactSvcPrimitiveType_String, PrimitiveType_String } },
+               {"addresses.postalCode",    { IF_SVC_ELSE(_contacts_address._uri, _contacts_address.contact_id, _contacts_address.postal_code, NULL, E_CONTACT_FIELD_LAST), ContactSearchEngine::ContactSvcPrimitiveType_String, PrimitiveType_String } },
+               {"addresses.isDefault",     { IF_SVC_ELSE(_contacts_address._uri, _contacts_address.contact_id, _contacts_address.is_default, NULL, E_CONTACT_FIELD_LAST), ContactSearchEngine::ContactSvcPrimitiveType_Boolean, PrimitiveType_Boolean } },
+               {"addresses.types",         { IF_SVC_ELSE(_contacts_address._uri, _contacts_address.contact_id, _contacts_address.type, NULL, E_CONTACT_FIELD_LAST), ContactSearchEngine::ContactSvcPrimitiveType_Int, PrimitiveType_Long } },
+               {"photoURI",                { IF_SVC_ELSE(_contacts_simple_contact._uri, _contacts_simple_contact.id, _contacts_simple_contact.image_thumbnail_path, EVC_PHOTO, E_CONTACT_FIELD_LAST), ContactSearchEngine::ContactSvcPrimitiveType_String, PrimitiveType_String } },
+               {"phoneNumbers.number",     { IF_SVC_ELSE(_contacts_number._uri, _contacts_number.contact_id, _contacts_number.number, EVC_TEL, E_CONTACT_FIELD_LAST), ContactSearchEngine::ContactSvcPrimitiveType_String, PrimitiveType_String } },
+               {"phoneNumbers.isDefault",  { IF_SVC_ELSE(_contacts_number._uri, _contacts_number.contact_id, _contacts_number.is_default, NULL, E_CONTACT_FIELD_LAST), ContactSearchEngine::ContactSvcPrimitiveType_Boolean, PrimitiveType_Boolean } },
+               {"phoneNumbers.types",      { IF_SVC_ELSE(_contacts_number._uri, _contacts_number.contact_id, _contacts_number.type, NULL, E_CONTACT_FIELD_LAST), ContactSearchEngine::ContactSvcPrimitiveType_Int, PrimitiveType_Long } },
+               {"emails.email",            { IF_SVC_ELSE(_contacts_email._uri, _contacts_email.contact_id, _contacts_email.email, EVC_EMAIL, E_CONTACT_FIELD_LAST), ContactSearchEngine::ContactSvcPrimitiveType_String, PrimitiveType_String } },
+               {"emails.isDefault",        { IF_SVC_ELSE(_contacts_email._uri, _contacts_email.contact_id, _contacts_email.is_default, NULL, E_CONTACT_FIELD_LAST), ContactSearchEngine::ContactSvcPrimitiveType_Boolean, PrimitiveType_Boolean } },
+               {"emails.types",            { IF_SVC_ELSE(_contacts_email._uri, _contacts_email.contact_id, _contacts_email.type, NULL, E_CONTACT_FIELD_LAST), ContactSearchEngine::ContactSvcPrimitiveType_Int, PrimitiveType_Long } },
+               {"birthday",                { IF_SVC_ELSE(_contacts_event._uri, _contacts_event.contact_id, _contacts_event.date, NULL, E_CONTACT_BIRTH_DATE), ContactSearchEngine::ContactSvcPrimitiveType_Int, PrimitiveType_Long } },
+               {"anniversaries.date",      { IF_SVC_ELSE(_contacts_event._uri, _contacts_event.contact_id, _contacts_event.date, NULL, E_CONTACT_FIELD_LAST), ContactSearchEngine::ContactSvcPrimitiveType_Int, PrimitiveType_Long } },
+               {"anniversaries.label",     { IF_SVC_ELSE(_contacts_event._uri, _contacts_event.contact_id, _contacts_event.label, NULL, E_CONTACT_FIELD_LAST), ContactSearchEngine::ContactSvcPrimitiveType_String, PrimitiveType_String } },
+               {"organizations.name",      { IF_SVC_ELSE(_contacts_company._uri, _contacts_company.contact_id, _contacts_company.name, NULL, E_CONTACT_ORG), ContactSearchEngine::ContactSvcPrimitiveType_String, PrimitiveType_String } },
+               {"organizations.department",{ IF_SVC_ELSE(_contacts_company._uri, _contacts_company.contact_id, _contacts_company.department, NULL, E_CONTACT_ORG_UNIT), ContactSearchEngine::ContactSvcPrimitiveType_String, PrimitiveType_String } },
+               {"organizations.title",     { IF_SVC_ELSE(_contacts_company._uri, _contacts_company.contact_id, _contacts_company.job_title, NULL, E_CONTACT_TITLE), ContactSearchEngine::ContactSvcPrimitiveType_String, PrimitiveType_String } },
+               {"organizations.role",      { IF_SVC_ELSE(_contacts_company._uri, _contacts_company.contact_id, _contacts_company.role, NULL, E_CONTACT_ROLE), ContactSearchEngine::ContactSvcPrimitiveType_String, PrimitiveType_String } },
+               {"organizations.logoURI",   { IF_SVC_ELSE(_contacts_company._uri, _contacts_company.contact_id, _contacts_company.logo, NULL, E_CONTACT_FIELD_LAST), ContactSearchEngine::ContactSvcPrimitiveType_String, PrimitiveType_String } },
+               {"organizations.assistant", { IF_SVC_ELSE(_contacts_company._uri, _contacts_company.contact_id, _contacts_company.assistant_name, NULL, E_CONTACT_ASSISTANT), ContactSearchEngine::ContactSvcPrimitiveType_String, PrimitiveType_String } },
+               {"organizations.location",  { IF_SVC_ELSE(_contacts_company._uri, _contacts_company.contact_id, _contacts_company.location, NULL, E_CONTACT_FIELD_LAST), ContactSearchEngine::ContactSvcPrimitiveType_String, PrimitiveType_String } },
+               {"organizations.description",  { IF_SVC_ELSE(_contacts_company._uri, _contacts_company.contact_id, _contacts_company.description, NULL, E_CONTACT_FIELD_LAST), ContactSearchEngine::ContactSvcPrimitiveType_String, PrimitiveType_String } },
+               {"organizations.phoneticName", { IF_SVC_ELSE(_contacts_company._uri, _contacts_company.contact_id, _contacts_company.phonetic_name, NULL, E_CONTACT_FIELD_LAST), ContactSearchEngine::ContactSvcPrimitiveType_String, PrimitiveType_String } },
+               {"organizations.type",      { IF_SVC_ELSE(_contacts_company._uri, _contacts_company.contact_id, _contacts_company.type, NULL, E_CONTACT_FIELD_LAST), ContactSearchEngine::ContactSvcPrimitiveType_String, PrimitiveType_Long } },
+               {"notes",                   { IF_SVC_ELSE(_contacts_note._uri, _contacts_note.contact_id, _contacts_note.note, NULL, E_CONTACT_NOTE), ContactSearchEngine::ContactSvcPrimitiveType_String, PrimitiveType_String } },
+               {"urls.url",                { IF_SVC_ELSE(_contacts_url._uri, _contacts_url.contact_id, _contacts_url.url, NULL, E_CONTACT_FIELD_LAST), ContactSearchEngine::ContactSvcPrimitiveType_String, PrimitiveType_String } },
+               {"urls.type",               { IF_SVC_ELSE(_contacts_url._uri, _contacts_url.contact_id, _contacts_url.type, NULL, E_CONTACT_FIELD_LAST), ContactSearchEngine::ContactSvcPrimitiveType_Int, PrimitiveType_Long } },
+               {"ringtoneURI",             { IF_SVC_ELSE(_contacts_simple_contact._uri, _contacts_simple_contact.id, _contacts_simple_contact.ringtone_path, NULL, E_CONTACT_FIELD_LAST), ContactSearchEngine::ContactSvcPrimitiveType_String, PrimitiveType_String } },
+               {"groupIds",                { IF_SVC_ELSE(_contacts_group_relation._uri, _contacts_group_relation.contact_id, _contacts_group_relation.group_id, NULL, E_CONTACT_FIELD_LAST), ContactSearchEngine::ContactSvcPrimitiveType_Int, PrimitiveType_Long } }
 };
 
-ContactSearchEngine::ContactSearchEngine() :
+ContactSearchEngine::ContactSearchEngine(
+#ifdef FEATURE_EBOOK
+                                        EBookClientCXX &ebook
+#endif
+
+                                        ) :
+#ifdef FEATURE_EBOOK
+               m_ebook(ebook),
+#endif
                m_addressBookId(0),
                m_isAddressBookIdSet(false),
                m_isFilterSet(false),
@@ -155,11 +178,19 @@ void ContactSearchEngine::setCondition(FilterPtr filter)
                return;
 
        IFilterVisitorPtr filterQuery = DPL::StaticPointerCast<IFilterVisitor>(SharedFromThis());
-       filter->travel(filterQuery);
 
+#ifdef FEATURE_EBOOK
+       // Set up root level of queries.
+       m_queries.clear();
+       m_queries.resize(1);
+       filter->travel(filterQuery);
+       m_isFilterSet = true;
+#else
+       filter->travel(filterQuery);
        if(m_filteredContactIds != NULL)
                m_isFilterSet = true;
-       }
+#endif
+}
 
 void ContactSearchEngine::setSortMode(SortModePtr attr)
 {
@@ -180,11 +211,95 @@ void ContactSearchEngine::setSortMode(SortModePtr attr)
 ContactArrayPtr ContactSearchEngine::getContactSearchResult()
 {
        ContactArrayPtr result(NULL);
-       unsigned int length = 0;
 
        LoggerD("entered");
+#ifdef FEATURE_EBOOK
+       if (!m_isSortModeSet && !m_isFilterSet) {
+               // Fast path: just read all contacts, unsorted.
+               result = getAllContacts();
+       } else {
+               result = ContactArrayPtr(new ContactArray);
+
+               // Sort and/or filtering using the EDS cursor API.
+               EBookQueryCXX query;
+               if (m_queries.empty() ||
+                   m_queries[0].empty()) {
+                       query.take(e_book_query_any_field_contains(""));
+               } else {
+                       query = m_queries[0][0];
+               }
+               PlainGStr sexp(e_book_query_to_string(query));
+               static EContactField sortFields[2] = {
+                       // Hard-coded sorting. Currently we don't have
+                       // support for choosing a specific order.
+                       E_CONTACT_FAMILY_NAME,
+                       E_CONTACT_GIVEN_NAME
+               };
+               EBookCursorSortType order = (!m_isSortModeSet || m_sortOrder == ASCENDING_SORT_ORDER) ?
+                       E_BOOK_CURSOR_SORT_ASCENDING :
+                       E_BOOK_CURSOR_SORT_DESCENDING;
+               EBookCursorSortType sortOrder[2] = {
+                       order, order
+               };
+
+               EBookClientCursorCXX cursor;
+               EBookClientCursor *tmpCursor;
+               GErrorCXX gerror;
+               if (!e_book_client_get_cursor_sync(m_ebook,
+                                                  sexp,
+                                                  sortFields,
+                                                  sortOrder,
+                                                  2, // entries in sortFields and sortOrder
+                                                  &tmpCursor,
+                                                  NULL,
+                                                  gerror)) {
+                       ThrowMsg(PlatformException, "e_book_client_get_cursors_sync: " << gerror.msg());
+               }
+               cursor.take(tmpCursor);
+               static const int stepSize = 1000;
+               while (true) {
+                       GSList *tmpContacts;
+                       gint num = e_book_client_cursor_step_sync(cursor,
+                                                                 (EBookCursorStepFlags)(E_BOOK_CURSOR_STEP_MOVE|E_BOOK_CURSOR_STEP_FETCH),
+                                                                 E_BOOK_CURSOR_ORIGIN_CURRENT,
+                                                                 stepSize,
+                                                                 &tmpContacts,
+                                                                 NULL,
+                                                                 gerror);
+                       if (num == -1) {
+                               ThrowMsg(PlatformException, "e_book_client_cursor_step_sync: " << gerror.msg());
+                       }
+                       contacts_list_h contacts(tmpContacts);
+                       BOOST_FOREACH (EContact *econtact, contacts) {
+                               contacts_record_h record(econtact, ADD_REF);
+                               ContactPtr contact(NULL);
+                               Try
+                                       {
+                                               ContactObjectP2AConverterPtr contactObjConverter(
+                                                                                                new ContactObjectP2AConverter(record,
+#ifdef FEATURE_EBOOK
+                                                                                                                              m_ebook,
+#endif
+                                                                                                                              false));
+                                               contact = contactObjConverter->getAbstractContact();
+                                       }
+                               Catch(Exception)
+                               {
+                                       LoggerW("fail to convert contact");
+                                       continue;
+                               }
+
+                               result->push_back(contact);
+                       }
+                       if (num < stepSize) {
+                               break;
+                       }
+               }
+       }
+#else
        if(m_isFilterSet)
        {
+               unsigned int length = 0;
                if(m_isSortModeSet)
                {
                        ContactIdArrayPtr ids = ContactIdArrayPtr(new ContactIdArray());
@@ -240,6 +355,7 @@ ContactArrayPtr ContactSearchEngine::getContactSearchResult()
                        result = getAllContacts();
                }
        }
+#endif
        LoggerD("End");
 
        return result;
@@ -247,9 +363,13 @@ ContactArrayPtr ContactSearchEngine::getContactSearchResult()
 
 void ContactSearchEngine::visitPreComposite(FilterType& type, int depth)
 {
+#ifdef FEATURE_EBOOK
+       m_queries.resize(m_queries.size() + 1);
+#else
        ContactIdSetArrayPtr idSets = ContactIdSetArrayPtr(new ContactIdSetArray());
 
        m_contactIdSetArrayStack.push(idSets);
+#endif
 }
 
 void ContactSearchEngine::visitInComposite(FilterType& type, int depth)
@@ -259,6 +379,20 @@ void ContactSearchEngine::visitInComposite(FilterType& type, int depth)
 
 void ContactSearchEngine::visitPostComposite(FilterType& type, int depth)
 {
+#ifdef FEATURE_EBOOK
+       CurrentQueries sub = m_queries.back();
+       m_queries.resize(m_queries.size() - 1);
+       CurrentQueries &current = m_queries.back();
+       EBookQueryCXX composite;
+       // Temporary array for EDS.
+       boost::scoped_array<EBookQuery *> buffer(new EBookQuery *[sub.size()]);
+       for (size_t i = 0; i < sub.size(); i++) {
+               buffer[i] = sub[i].get();
+       }
+       composite.take((type == UNION_FILTER ? e_book_query_or : e_book_query_and)
+                      (sub.size(), buffer.get(), false));
+       current.push_back(composite);
+#else
        ContactIdSetArrayPtr idSets = m_contactIdSetArrayStack.top();
        m_contactIdSetArrayStack.pop();
 
@@ -281,6 +415,7 @@ void ContactSearchEngine::visitPostComposite(FilterType& type, int depth)
                        parentIdSets->push_back(idSet);
                }
        }
+#endif
 }
 
 void ContactSearchEngine::visitAttribute(string& attrName, MatchFlag& matchFlag, AnyPtr& matchValue, int depth)
@@ -288,6 +423,69 @@ void ContactSearchEngine::visitAttribute(string& attrName, MatchFlag& matchFlag,
        if(matchValue == NULL || matchValue->isNullOrUndefined())
                matchFlag = MATCH_EXISTS;
 
+#ifdef FEATURE_EBOOK
+       AttributePropertiesMap::iterator iter =
+                       attributePropertiesMap.find(attrName);
+       if (iter == attributePropertiesMap.end())
+               ThrowMsg(NotFoundException, "There is no attribute name for filter : " << attrName);
+       AttributeProperties &properties = iter->second;
+       if (!properties.vCardField && properties.contactField == E_CONTACT_FIELD_LAST)
+               ThrowMsg(UnsupportedException, "Filtering by this field not supported: " << attrName);
+       string value;
+       if (properties.jsType == PrimitiveType_String) {
+               value = matchValue->getString();
+       } else if (matchFlag != MATCH_EXISTS) {
+               // Only string value matches are supported. Other
+               // fields can only be checked for existence.
+               ThrowMsg(UnsupportedException, "Filtering field " << attrName << " by value is not supported.");
+       }
+       EBookQueryCXX query;
+       if (properties.vCardField) {
+               switch (matchFlag) {
+               case MATCH_EXISTS:
+                       query.take(e_book_query_vcard_field_exists(properties.vCardField));
+                       break;
+               case MATCH_EXACTLY:
+                       // Matching exactly is not supported accurately. Fall back to
+                       // less exact full string comparison.
+               case MATCH_FULLSTRING:
+                       query.take(e_book_query_vcard_field_test(properties.vCardField, E_BOOK_QUERY_IS, value.c_str()));
+                       break;
+               case MATCH_STARTSWITH:
+                       query.take(e_book_query_vcard_field_test(properties.vCardField, E_BOOK_QUERY_BEGINS_WITH, value.c_str()));
+                       break;
+               case MATCH_ENDSWITH:
+                       query.take(e_book_query_vcard_field_test(properties.vCardField, E_BOOK_QUERY_ENDS_WITH, value.c_str()));
+               case MATCH_CONTAINS:
+                       query.take(e_book_query_vcard_field_test(properties.vCardField, E_BOOK_QUERY_CONTAINS, value.c_str()));
+               case MATCH_NONE:
+                       break;
+               }
+       } else {
+               switch (matchFlag) {
+               case MATCH_EXISTS:
+                       query.take(e_book_query_field_exists(properties.contactField));
+                       break;
+               case MATCH_EXACTLY:
+                       // Matching exactly is not supported accurately. Fall back to
+                       // less exact full string comparison.
+               case MATCH_FULLSTRING:
+                       query.take(e_book_query_field_test(properties.contactField, E_BOOK_QUERY_IS, value.c_str()));
+                       break;
+               case MATCH_STARTSWITH:
+                       query.take(e_book_query_field_test(properties.contactField, E_BOOK_QUERY_BEGINS_WITH, value.c_str()));
+                       break;
+               case MATCH_ENDSWITH:
+                       query.take(e_book_query_field_test(properties.contactField, E_BOOK_QUERY_ENDS_WITH, value.c_str()));
+               case MATCH_CONTAINS:
+                       query.take(e_book_query_field_test(properties.contactField, E_BOOK_QUERY_CONTAINS, value.c_str()));
+               case MATCH_NONE:
+                       break;
+               }
+       }
+       CurrentQueries &current = m_queries.back();
+       current.push_back(query);
+#else
        ContactIdSetPtr idSet = ContactIdSetPtr(new ContactIdSet());
 
        if(attrName == "id")
@@ -413,10 +611,14 @@ void ContactSearchEngine::visitAttribute(string& attrName, MatchFlag& matchFlag,
                        parentIdSets->push_back(idSet);
                }
        }
+#endif
 }
 
 void ContactSearchEngine::visitAttributeRange(string& attrName, AnyPtr& initialValue, AnyPtr& endValue, int depth)
 {
+#ifdef FEATURE_EBOOK
+       ThrowMsg(UnsupportedException, "Filtering by value range is not supported.");
+#else
        ContactIdSetPtr idSet = ContactIdSetPtr(new ContactIdSet());
 
        bool initialValueIsSet = true;
@@ -551,8 +753,10 @@ void ContactSearchEngine::visitAttributeRange(string& attrName, AnyPtr& initialV
                ContactIdSetArrayPtr parentIdSets = m_contactIdSetArrayStack.top();
                parentIdSets->push_back(idSet);
        }
+#endif
 }
 
+#ifndef FEATURE_EBOOK
 ContactArrayPtr ContactSearchEngine::getAllContactsSorted(AttributeProperties& attributeProperties, bool is_ascending)
 {
        ContactArrayPtr contacts = ContactArrayPtr(new ContactArray());
@@ -588,13 +792,23 @@ ContactArrayPtr ContactSearchEngine::getAllContactsSorted(AttributeProperties& a
 
        return contacts;
 }
+#endif
 
 ContactArrayPtr ContactSearchEngine::getAllContacts()
 {
-       int errorCode = 0;
-
        ContactArrayPtr contacts(new ContactArray());
-       contacts_list_h list = NULL;
+       contacts_list_h list(NULL);
+
+#ifdef FEATURE_EBOOK
+       EBookQueryCXX allItemsQuery(e_book_query_any_field_contains(""), TRANSFER_REF);
+       PlainGStr sexp(e_book_query_to_string (allItemsQuery.get()));
+       GSList *elist;
+       GErrorCXX gerror;
+       if (!e_book_client_get_contacts_sync(m_ebook, sexp, &elist, NULL, gerror))
+               ThrowMsg(PlatformException, "e_book_client_get_contacts_sync: " << gerror.msg());
+       list.reset(elist);
+#else
+       int errorCode = 0;
 
        if(!m_isAddressBookIdSet)
        {
@@ -641,10 +855,18 @@ ContactArrayPtr ContactSearchEngine::getAllContacts()
        if(errorCode != CONTACTS_ERROR_NONE)
                ThrowMsg(PlatformException, "Fail to get contacts_list_get_count : " << errorCode << " (" << __FUNCTION__ << ")");
        LoggerD("END: pure contact-svc");
+#endif
 
+#ifdef FEATURE_EBOOK
+       BOOST_FOREACH (EContact *econtact, list)
+#else
        contacts_list_first(list);
        for(unsigned int i=0; i<record_count; i++)
+#endif
        {
+#ifdef FEATURE_EBOOK
+               contacts_record_h record(econtact, ADD_REF);
+#else
                contacts_record_h record;
                errorCode = contacts_list_get_current_record_p(list, &record);
                if(errorCode != CONTACTS_ERROR_NONE || record == NULL)
@@ -652,12 +874,17 @@ ContactArrayPtr ContactSearchEngine::getAllContacts()
                        LoggerW("contacts_list_get_current_record_p error : " << errorCode << " (" << __FUNCTION__ << ")");
                        continue;
                }
+#endif
 
                ContactPtr contact(NULL);
                Try
                {
                        ContactObjectP2AConverterPtr contactObjConverter(
-                                       new ContactObjectP2AConverter(record, false));
+                                       new ContactObjectP2AConverter(record,
+#ifdef FEATURE_EBOOK
+                                                                     m_ebook,
+#endif
+                                                                     false));
 
                        contact = contactObjConverter->getAbstractContact();
                }
@@ -669,10 +896,12 @@ ContactArrayPtr ContactSearchEngine::getAllContacts()
 
                contacts->push_back(contact);
 
+#ifndef FEATURE_EBOOK
                contacts_list_next(list);
+#endif
        }
 
-       if(list != NULL)
+       if(list)
                contacts_list_destroy(list, true);
 
        LoggerD("END: convertToPlugin Objects");
@@ -680,6 +909,7 @@ ContactArrayPtr ContactSearchEngine::getAllContacts()
        return contacts;
 }
 
+#ifndef FEATURE_EBOOK
 ContactArrayPtr ContactSearchEngine::getContacts(ContactIdArrayPtr& ids)
 {
        ContactArrayPtr contacts(new ContactArray());
@@ -753,7 +983,11 @@ ContactPtr ContactSearchEngine::getContact(int id)
        }
 
        ContactObjectP2AConverterPtr contactObjConverter(
-                       new ContactObjectP2AConverter(record, false));
+                       new ContactObjectP2AConverter(record,
+#ifdef FEATURE_EBOOK
+                                                     m_ebook,
+#endif
+                                                     false));
        ContactPtr contact = contactObjConverter->getAbstractContact();
 
        return contact;
@@ -1355,5 +1589,7 @@ void ContactSearchEngine::getUnion(ContactIdSetArrayPtr& idSets, ContactIdSetPtr
        }
 }
 
+#endif // FEATURE_EBOOK
+
 } // Contact
 } // DeviceAPI
index a9bdc41..0129c17 100755 (executable)
@@ -46,7 +46,11 @@ class ContactSearchEngine :
        public DPL::EnableSharedFromThis<ContactSearchEngine>
 {
 public:
-       ContactSearchEngine();
+       ContactSearchEngine(
+#ifdef FEATURE_EBOOK
+                           EBookClientCXX &ebook
+#endif
+                           );
        virtual ~ContactSearchEngine();
 
        // setting search options.
@@ -80,14 +84,28 @@ public:
 
        struct AttributeProperties
        {
+#ifdef FEATURE_EBOOK
+               const gchar *vCardField;
+               const EContactField contactField;
+#else
                const char* viewUri;
                const unsigned int propertyContactId;
                const unsigned int propertyId;
+#endif
                const ContactSvcPrimitiveType type;
                const DeviceAPI::Tizen::PrimitiveType jsType;
        };
        typedef std::map<std::string, AttributeProperties> AttributePropertiesMap;
 
+#ifdef FEATURE_EBOOK
+       // When using EDS, the JS search query is translated into an EBookQuery
+       // and one search operation is executed which returns the final result
+       // data immediately.
+#else
+       // When using contacts service, each JS term triggers one DB
+       // search operation. The ContactSearchEngine then combines the
+       // results and as a last step, retrieves the data for the final
+       // result set.
        typedef std::vector<int> ContactIdArray;
        typedef DPL::SharedPtr<ContactIdArray> ContactIdArrayPtr;
 
@@ -96,19 +114,34 @@ public:
 
        typedef std::vector<ContactIdSetPtr> ContactIdSetArray;
        typedef DPL::SharedPtr<ContactIdSetArray> ContactIdSetArrayPtr;
+#endif
 
 private:
        static AttributePropertiesMap attributePropertiesMap;
 
+#ifdef FEATURE_EBOOK
+       EBookClientCXX m_ebook;
+#endif
        int m_addressBookId;
        bool m_isAddressBookIdSet;
        bool m_isFilterSet;
        bool m_isSortModeSet;
 
+#ifdef FEATURE_EBOOK
+       typedef std::vector<EBookQueryCXX> CurrentQueries;
+       typedef std::vector<CurrentQueries> SubQueries;
+
+       // Grows when entering a composite query, shrinks
+       // when leaving it. At each level it contains the queries
+       // which need to be combined to form the composite query.
+       // The final query to run is m_queries[0][0].
+       SubQueries m_queries;
+#else
        std::stack<ContactIdSetArrayPtr> m_contactIdSetArrayStack;
        // NULL means ALL
        ContactIdSetPtr m_filteredContactIds;
        ContactIdArrayPtr m_sortedContactIds;
+#endif
 
        DeviceAPI::Tizen::SortOrder m_sortOrder;
        std::string m_attributeNameForSort;
@@ -117,6 +150,8 @@ private:
        ContactArrayPtr getAllContactsSorted(AttributeProperties& attributeProperties,
                        bool is_ascending);
        ContactArrayPtr getAllContacts();
+
+#ifndef FEATURE_EBOOK
        ContactArrayPtr getContacts(ContactIdArrayPtr& ids);
        ContactArrayPtr getContacts(ContactIdSetPtr& ids);
        ContactPtr getContact(int id);
@@ -144,6 +179,7 @@ private:
 
        void getIntersection(ContactIdSetArrayPtr& idSets, ContactIdSetPtr& result);
        void getUnion(ContactIdSetArrayPtr& idSets, ContactIdSetPtr& result);
+#endif
 };
 
 typedef DPL::SharedPtr<ContactSearchEngine> ContactSearchEnginePtr;
index 654a797..053d2d3 100755 (executable)
  * @brief
  */
 
+#ifdef FEATURE_EBOOK
+// Changes have to be watched by each AddressBook individually.
+#else
+
 #include "ContactsSvcChangeListenerManager.h"
 #include <contacts.h>
 #include <dpl/singleton_impl.h>
@@ -643,3 +647,5 @@ void ContactsSvcChangeListenerManager::personsChangedCallback(char* changes)
 
 } // Application
 } // DeviceAPI
+
+#endif // FEATURE_EBOOK
index 1f592b1..98e4234 100755 (executable)
 #ifndef TIZENAPIS_PLATFORM_CONTACT_CONTACT_LISTENER_MANAGER_H_
 #define TIZENAPIS_PLATFORM_CONTACT_CONTACT_LISTENER_MANAGER_H_
 
+#ifdef FEATURE_EBOOK
+// Changes have to be watched by each AddressBook individually. This
+// code simply does nothing.
+
+class IContactsSvcContactsChangeListener {};
+class IContactsSvcPersonsChangeListener {};
+
+#else
+
 #include <string>
 #include <map>
 #include <set>
@@ -131,4 +140,6 @@ typedef DPL::Singleton<ContactsSvcChangeListenerManager> ContactsSvcChangeListen
 } // Contact
 } // DeviceAPI
 
+#endif // FEATURE_EBOOK
+
 #endif // TIZENAPIS_PLATFORM_CONTACT_CONTACT_LISTENER_MANAGER_H_
index 4e34980..03e85e3 100755 (executable)
@@ -38,7 +38,9 @@ namespace Contact {
 using namespace WrtDeviceApis::Commons;
 using namespace std;
 
+#ifndef FEATURE_EBOOK
 static const char *EMPTY_STRING = "";
+#endif
 
 ContactsSvcObjectConverter::ContactsSvcObjectConverter()
 {
@@ -50,6 +52,9 @@ ContactsSvcObjectConverter::~ContactsSvcObjectConverter()
 
 void ContactsSvcObjectConverter::convertToAbstract(contacts_record_h record, PersonPtr& person)
 {
+#ifdef FEATURE_EBOOK
+       ThrowMsg(UnsupportedException, "person concept not supported");
+#else
        if(record == NULL)
        {
                ThrowMsg(InvalidArgumentException, "Platform person object did not set");
@@ -146,10 +151,14 @@ void ContactsSvcObjectConverter::convertToAbstract(contacts_record_h record, Per
                ThrowMsg(PlatformException, "error on contacts_record_get_int (display_contact_id) (errorCode:" << errorCode << ")");
 
        person->setDisplayContactId(intValue);
+#endif
 }
 
 void ContactsSvcObjectConverter::convertToPlatform(PersonPtr& person, contacts_record_h record)
 {
+#ifdef FEATURE_EBOOK
+       ThrowMsg(UnsupportedException, "person concept not supported");
+#else
        if(record == NULL)
        {
                ThrowMsg(InvalidArgumentException, "Platform person object did not set");
@@ -383,6 +392,7 @@ void ContactsSvcObjectConverter::convertToPlatform(PersonPtr& person, contacts_r
        {
                ThrowMsg(PlatformException, "importing displayContactId E (err:" << errorCode << ", value:" << intValue << ")");
        }
+#endif
 }
 
 void ContactsSvcObjectConverter::convertToAbstract(contacts_record_h record, ContactPtr& contact)
@@ -397,6 +407,9 @@ void ContactsSvcObjectConverter::convertToPlatform(ContactPtr& contact, contacts
 
 void ContactsSvcObjectConverter::convertToAbstract(contacts_record_h record, ContactGroupPtr& group)
 {
+#ifdef FEATURE_EBOOK
+       ThrowMsg(UnsupportedException, "person concept not supported");
+#else
        if(record == NULL)
        {
                ThrowMsg(InvalidArgumentException, "Platform group object did not set");
@@ -579,6 +592,7 @@ void ContactsSvcObjectConverter::convertToPlatform(ContactGroupPtr& group, conta
                        ThrowMsg(PlatformException, "importing ringtoneURI E (err:" << errorCode);
                }
        }
+#endif
 }
 
 } // Contact
index ef7b9ed..b249300 100755 (executable)
@@ -40,16 +40,19 @@ using namespace WrtDeviceApis::Commons;
 // Caution : This class MUST be used on an identical thread.
 
 ContactsSvcWrapper::ContactsSvcWrapper() :
-       m_opened(false),
-       m_defaultAddressBook(NULL),
+       m_opened(false)
+#ifndef FEATURE_EBOOK
+       , m_defaultAddressBook(NULL),
        m_unifiedAddressBook(NULL),
        m_addressBooks(new AddressBookArray())
+#endif
 {
        init();
 }
 
 ContactsSvcWrapper::~ContactsSvcWrapper()
 {
+#ifndef FEATURE_EBOOK
        //when it is last instance then close connection to database
        if(m_opened)
        {
@@ -60,6 +63,7 @@ ContactsSvcWrapper::~ContactsSvcWrapper()
                        LoggerE("Error occurred during closing contacts database. (ret:" << ret << ")");
                }
        }
+#endif
 }
 
 AddressBookPtr ContactsSvcWrapper::getAddressBook(const std::string &id)
@@ -72,6 +76,12 @@ AddressBookPtr ContactsSvcWrapper::getAddressBook(const std::string &id)
                ThrowMsg(PlatformException, "Contact DB is not open.");
        }
 
+#ifdef FEATURE_EBOOK
+       AddressBooks_t::const_iterator it = m_addressBooks.find(id == "0" ? "system-address-book" : id);
+       if (it == m_addressBooks.end())
+               ThrowMsg(NotFoundException, "Address book not found");
+       return it->second;
+#else
        if(m_idMap.find(id) == m_idMap.end())
                ThrowMsg(NotFoundException, "No AddressBook1 ");
 
@@ -81,6 +91,7 @@ AddressBookPtr ContactsSvcWrapper::getAddressBook(const std::string &id)
                ThrowMsg(NotFoundException, "No AddressBook2 ");
 
        return m_addressBooks->at(index);
+#endif
 }
 
 AddressBookPtr ContactsSvcWrapper::getDefaultAddressBook()
@@ -93,10 +104,19 @@ AddressBookPtr ContactsSvcWrapper::getDefaultAddressBook()
                ThrowMsg(PlatformException, "Contact DB is not open.");
        }
 
+#ifdef FEATURE_EBOOK
+       ESourceCXX esource(e_source_registry_ref_default_address_book(m_sourceRegistry), TRANSFER_REF);
+       AddressBooks_t::const_iterator it = m_addressBooks.find(e_source_get_uid(esource));
+       if (it == m_addressBooks.end())
+               ThrowMsg(NotFoundException, "Default address book not found");
+       return it->second;
+#else
        if(m_addressBooks->size() == 0)
                ThrowMsg(PlatformException, "Invalid request");
 
        return m_defaultAddressBook;
+#endif
+
 }
 
 AddressBookPtr ContactsSvcWrapper::getUnifiedAddressBook()
@@ -109,10 +129,15 @@ AddressBookPtr ContactsSvcWrapper::getUnifiedAddressBook()
                ThrowMsg(PlatformException, "Contact DB is not open.");
        }
 
+#ifdef FEATURE_EBOOK
+       ThrowMsg(UnsupportedException, "Unified address book not supported");
+       return AddressBookPtr();
+#else
        if(m_addressBooks->size() == 0)
                ThrowMsg(PlatformException, "Invalid request");
 
        return m_unifiedAddressBook;
+#endif
 }
 
 AddressBookArrayPtr ContactsSvcWrapper::getAddressBooks()
@@ -127,8 +152,13 @@ AddressBookArrayPtr ContactsSvcWrapper::getAddressBooks()
 
        AddressBookArrayPtr newArray(new AddressBookArray());
 
+#ifdef FEATURE_EBOOK
+       BOOST_FOREACH (const AddressBooks_t::value_type &entry, m_addressBooks)
+               newArray->push_back(entry.second);
+#else
        for(AddressBookArray::iterator i = m_addressBooks->begin(); i != m_addressBooks->end(); i++)
                newArray->push_back(*i);
+#endif
 
        return newArray;
 }
@@ -140,6 +170,25 @@ void ContactsSvcWrapper::init()
 
        LoggerD("entered");
 
+#ifdef FEATURE_EBOOK
+       if (!access("/tmp/debug-contacts", R_OK)) {
+               FILE *f = fopen("/tmp/contacts-wrt.pid", "w");
+               fprintf(f, "%ld", (long)getpid());
+               fclose(f);
+               sleep(10);
+       }
+
+       GErrorCXX gerror;
+       m_sourceRegistry.take(e_source_registry_new_sync(NULL, gerror));
+       if (!m_sourceRegistry) {
+               LoggerE("Error occurred during creation of ESourceRegistry: " << gerror.msg());
+               return;
+       }
+       m_sourceRegistry.connectSignal<void(ESource *)>("source-added", boost::bind(&ContactsSvcWrapper::addSource, this, _1));
+       m_sourceRegistry.connectSignal<void(ESource *)>("source-enabled", boost::bind(&ContactsSvcWrapper::addSource, this, _1));
+       m_sourceRegistry.connectSignal<void(ESource *)>("source-removed", boost::bind(&ContactsSvcWrapper::removeSource, this, _1));
+       m_sourceRegistry.connectSignal<void(ESource *)>("source-disabled", boost::bind(&ContactsSvcWrapper::removeSource, this, _1));
+#else
        int ret = contacts_connect2();
        if (ret != CONTACTS_ERROR_NONE)
        {
@@ -150,6 +199,7 @@ void ContactsSvcWrapper::init()
 
                return;
        }
+#endif
 
        //contacts-service has properly connected.
        LoggerD("Contact db has properly opened.");
@@ -162,6 +212,11 @@ void ContactsSvcWrapper::loadAddressBooks()
 {
        LoggerD("Loading AddressBook");
 
+#ifdef FEATURE_EBOOK
+       ESourceList esources(e_source_registry_list_sources(m_sourceRegistry, E_SOURCE_EXTENSION_ADDRESS_BOOK));
+       BOOST_FOREACH (ESource *esource, esources)
+               addSource(esource);
+#else
        int errorCode = 0;
        contacts_list_h addressbooks_list = NULL;
 
@@ -263,8 +318,57 @@ void ContactsSvcWrapper::loadAddressBooks()
                        contacts_list_destroy(addressbooks_list, true);
                return;
        }
+#endif
+}
+
+#ifdef FEATURE_EBOOK
+
+void ContactsSvcWrapper::addSource(ESource *esource)
+{
+       // Don't add when not enabled or not an address book.
+       if (!e_source_get_enabled(esource) ||
+           !e_source_has_extension(esource, E_SOURCE_EXTENSION_ADDRESS_BOOK))
+               return;
+
+       // Don't add again when already known.
+       const char *uid = e_source_get_uid(esource);
+       AddressBooks_t::const_iterator it = m_addressBooks.find(uid);
+       if (it != m_addressBooks.end())
+               return;
+
+       // Open address book now. AddressBook itself has no notion of
+       // "opening" itself.
+       GErrorCXX gerror;
+       EBookClientCXX ebook(E_BOOK_CLIENT(e_book_client_connect_direct_sync(m_sourceRegistry, esource, NULL, gerror)), TRANSFER_REF);
+       if (!ebook) {
+               LoggerE("Error occurred when opening address book " << uid << ": " << gerror.msg());
+               return;
+       }
+
+       AddressBookPtr addressBook(new AddressBook(ebook));
+       const char *name = e_source_get_display_name(esource);
+       addressBook->setName(name);
+       // Strictly speaking, this is IVI specific: in IVI, only the system address book
+       // is writable. Everything else are currently cached address books from phones
+       // which must not be modified even though EDS would allow it.
+       //
+       // TODO: add a "data not writable" flag to the registry.
+       ESourceCXX sysSource(e_source_registry_ref_builtin_address_book(m_sourceRegistry), TRANSFER_REF);
+       addressBook->setReadOnly(!e_source_equal(esource, sysSource));
+
+       m_addressBooks.insert(AddressBooks_t::value_type(uid, addressBook));
 }
 
+void ContactsSvcWrapper::removeSource(ESource *esource)
+{
+       const char *uid = e_source_get_uid(esource);
+       AddressBooks_t::const_iterator it = m_addressBooks.find(uid);
+       if (it != m_addressBooks.end())
+               m_addressBooks.erase(it);
+ }
+
+#else // FEATURE_EBOOK
+
 int ContactsSvcWrapper::size() const
 {
        return m_idMap.size();
@@ -282,5 +386,7 @@ void ContactsSvcWrapper::insert(AddressBookPtr addressBook)
        m_addressBooks->push_back(addressBook);
 }
 
+#endif // FEATURE_EBOOK
+
 } // Contact
 } // DeviceAPI
index 0949dc8..1b0850a 100755 (executable)
@@ -29,6 +29,7 @@
 #include <map>
 #include <dpl/shared_ptr.h>
 #include <dpl/singleton.h>
+#include <contacts.h>
 #include "IAddressBook.h"
 
 namespace DeviceAPI {
@@ -49,16 +50,27 @@ private:
        void init();
 
        void loadAddressBooks();
+#ifdef FEATURE_EBOOK
+       void addSource(ESource *esource);
+       void removeSource(ESource *esource);
+#else
        void insert(AddressBookPtr addressBook);
        int size() const;
+#endif
 
 private:
        bool m_opened;
 
+#ifdef FEATURE_EBOOK
+       ESourceRegistryCXX m_sourceRegistry;
+       typedef std::map<std::string, AddressBookPtr> AddressBooks_t;
+       AddressBooks_t m_addressBooks;
+#else
        AddressBookPtr m_defaultAddressBook;
         AddressBookPtr m_unifiedAddressBook;
        AddressBookArrayPtr m_addressBooks;
        std::map<std::string, int> m_idMap;
+#endif
 };
 typedef DPL::Singleton<ContactsSvcWrapper> ContactsSvcWrapperSingleton;
 
index ff29063..6fffd54 100755 (executable)
@@ -94,7 +94,7 @@ public:
        virtual void getGroups(const EventAddressBookGetGroupsPtr &event);
 
        virtual std::string getId() const = 0;
-       virtual void        setId(const std::string &value) = 0;
+       // virtual void        setId(const std::string &value) = 0;
        virtual std::string getName() const = 0;
        virtual void        setName(const std::string &value) = 0;
        virtual std::string getAccountId() const = 0;
index e6bd7ed..6df0468 100755 (executable)
@@ -309,8 +309,9 @@ JSValueRef JSAddressBook::get(JSContextRef context,
                return JSWebAPIErrorFactory::postException(context, exception, JSWebAPIErrorFactory::TYPE_MISMATCH_ERROR, "");
        }
 
-       if(!ContactUtility::checkStrIsUInt(id))
-               return JSWebAPIErrorFactory::postException(context, exception, JSWebAPIErrorFactory::INVALID_VALUES_ERROR, "");
+       // See JSAddressBook::remove() - doesn't have be an integer.
+       // if(!ContactUtility::checkStrIsUInt(id))
+       //      return JSWebAPIErrorFactory::postException(context, exception, JSWebAPIErrorFactory::INVALID_VALUES_ERROR, "");
 
        EventAddressBookGetPtr dplEvent(new EventAddressBookGet());
 
@@ -759,8 +760,12 @@ JSValueRef JSAddressBook::remove(JSContextRef context,
        } catch(const NullPointerException& err) {
                return JSWebAPIErrorFactory::postException(context, exception, JSWebAPIErrorFactory::TYPE_MISMATCH_ERROR, "");
        }
-       if(!ContactUtility::checkStrIsUInt(contactId))
-               return JSWebAPIErrorFactory::postException(context, exception, JSWebAPIErrorFactory::INVALID_VALUES_ERROR, "");
+       // JS API does not require the ID to be an int. This checks must be done
+       // in the storage layer, if IDs are ints there. AddressBook::OnRequestReceived()
+       // does this, so this check here is redundant for Contacts Service 2 and
+       // incorrect for Evolution Data Server.
+       // if(!ContactUtility::checkStrIsUInt(contactId))
+       //      return JSWebAPIErrorFactory::postException(context, exception, JSWebAPIErrorFactory::INVALID_VALUES_ERROR, "");
 
        EventAddressBookRemovePtr dplEvent(new EventAddressBookRemove());
 
index 4057872..831222b 100755 (executable)
@@ -56,22 +56,25 @@ void Person::OnRequestReceived(const EventPersonLinkPtr &event)
 {
        LoggerD("entered");
 
-       int errorCode = 0;
        contacts_record_h contacts_record = NULL;
 
-       int selfPersonId = 0;
-       int personId = 0;
-
        Try
        {
                if(!event->getPersonIdIsSet())
                        ThrowMsg(InvalidArgumentException, "person id were not set.");
 
+#ifdef FEATURE_EBOOK
+               event->setResult(false);
+               event->setExceptionCode(ExceptionCodes::UnsupportedException);
+               return;
+#else
                string personIdStr = event->getPersonId();
 
                if(!ContactUtility::checkStrIsUInt(personIdStr))
                        ThrowMsg(InvalidArgumentException, "wrong " );
 
+               int selfPersonId = 0;
+               int personId = 0;
                try {
                        personId = ContactUtility::strToInt(personIdStr);
                        selfPersonId = ContactUtility::strToInt(m_id);
@@ -79,7 +82,7 @@ void Person::OnRequestReceived(const EventPersonLinkPtr &event)
                        ThrowMsg(InvalidArgumentException, "invalid" );
                }
 
-               errorCode = contacts_db_get_record(_contacts_person._uri, personId, &contacts_record);
+               int errorCode = contacts_db_get_record(_contacts_person._uri, personId, &contacts_record);
                if(errorCode != CONTACTS_ERROR_NONE)
                {
                        contacts_record_destroy(contacts_record, true);
@@ -110,6 +113,7 @@ void Person::OnRequestReceived(const EventPersonLinkPtr &event)
 
                event->setResult(true);
                event->setExceptionCode(ExceptionCodes::None);
+#endif
        }
        Catch (InvalidArgumentException)
        {
@@ -143,9 +147,6 @@ void Person::OnRequestReceived(const EventPersonUnlinkPtr &event)
 {
        LoggerD("entered");
 
-       int errorCode = 0;
-       int selfPersonId;
-       int contactId;
        contacts_record_h contacts_record = NULL;
 
        Try
@@ -153,11 +154,18 @@ void Person::OnRequestReceived(const EventPersonUnlinkPtr &event)
                if(!event->getContactIdIsSet())
                        ThrowMsg(InvalidArgumentException, "contact id were not set.");
 
+#ifdef FEATURE_EBOOK
+               event->setResult(false);
+               event->setExceptionCode(ExceptionCodes::UnsupportedException);
+               return;
+#else
                string contactIdStr = event->getContactId();
 
                if(!ContactUtility::checkStrIsUInt(contactIdStr))
                        ThrowMsg(InvalidArgumentException, "wrong" );
 
+               int selfPersonId;
+               int contactId;
                try {
                        selfPersonId = ContactUtility::strToInt(m_id);
                        contactId = ContactUtility::strToInt(contactIdStr);
@@ -165,7 +173,7 @@ void Person::OnRequestReceived(const EventPersonUnlinkPtr &event)
                        ThrowMsg(InvalidArgumentException, "invalid" );
                }
 
-               errorCode = contacts_db_get_record(_contacts_simple_contact._uri, contactId, &contacts_record);
+               int errorCode = contacts_db_get_record(_contacts_simple_contact._uri, contactId, &contacts_record);
                if(errorCode != CONTACTS_ERROR_NONE)
                {
                        contacts_record_destroy(contacts_record, true);
@@ -188,7 +196,7 @@ void Person::OnRequestReceived(const EventPersonUnlinkPtr &event)
                }
 
                int newPersonId = 0;
-               int errorCode = contacts_person_unlink_contact(selfPersonId, contactId, &newPersonId);
+               errorCode = contacts_person_unlink_contact(selfPersonId, contactId, &newPersonId);
                if(errorCode == CONTACTS_ERROR_INVALID_PARAMETER)
                        ThrowMsg(NotFoundException, "Error during executing contacts_person_unlink_contact()");
                else if (errorCode != CONTACTS_ERROR_NONE)
@@ -221,6 +229,7 @@ void Person::OnRequestReceived(const EventPersonUnlinkPtr &event)
 
                event->setResult(true);
                event->setExceptionCode(ExceptionCodes::None);
+#endif
        }
        Catch (InvalidArgumentException)
        {
@@ -256,7 +265,7 @@ void Person::OnRequestReceived(const EventPersonUnlinkPtr &event)
                return;
        }
 
-       if(contacts_record != NULL)
+       if(contacts_record)
                contacts_record_destroy(contacts_record, true);
 }
 
index fa046cc..c9a4c94 100755 (executable)
@@ -39,6 +39,8 @@ using namespace WrtDeviceApis::Commons;
 using namespace DeviceAPI::Tizen;
 using namespace std;
 
+#ifndef FEATURE_EBOOK
+
 map<string, PersonSearchEngine::FilterPropertyStruct> PersonSearchEngine::attrEnumMap = {
                {"id",                                          { _contacts_person.id,                  PrimitiveType_Long } },
                {"displayName",                         { _contacts_person.display_name,        PrimitiveType_String } },
@@ -473,5 +475,7 @@ void PersonSearchEngine::visitAttributeRange(string& attrName, AnyPtr& initialVa
        }
 }
 
+#endif // FEATURE_EBOOK
+
 } // Contact
 } // DeviceAPI
index cdf128b..e43f422 100755 (executable)
@@ -40,6 +40,8 @@
 namespace DeviceAPI {
 namespace Contact {
 
+#ifndef FEATURE_EBOOK
+
 class PersonSearchEngine :
        public DeviceAPI::Tizen::IFilterVisitor,
        public DPL::EnableSharedFromThis<PersonSearchEngine>
@@ -83,6 +85,8 @@ private:
 
 typedef DPL::SharedPtr<PersonSearchEngine> PersonSearchEnginePtr;
 
+#endif // FEATURE_EBOOK
+
 } // Contact
 } // DeviceAPI
 
diff --git a/src/Contact/contacts2ebook/GLibSupport.h b/src/Contact/contacts2ebook/GLibSupport.h
new file mode 100644 (file)
index 0000000..1886b3d
--- /dev/null
@@ -0,0 +1,515 @@
+//
+// Tizen Web Device API
+// Copyright (c) 2011-2013 Intel
+//
+// Licensed under the Apache License, Version 2.0 (the License);
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+//
+// This code simplifies using glib C APIs by providing RAII classes
+// and boost::function callbacks for GObject signals.
+//
+// The code was originally written for the SyncEvolution project,
+// where it was published by Intel under the LGPL 2.1. Intel is the sole
+// copyright owner and publishes it here under the Apache license as
+// indicated above.
+//
+
+#ifndef _PLATFORM_CONTACT_CONTACTS2EBOOK_GLIB_SUPPORT_H_
+#define _PLATFORM_CONTACT_CONTACTS2EBOOK_GLIB_SUPPORT_H_
+
+#include <glib.h>
+
+#include <boost/shared_ptr.hpp>
+#include <boost/intrusive_ptr.hpp>
+#include <boost/utility.hpp>
+#include <boost/foreach.hpp>
+#include <boost/function.hpp>
+#include <boost/bind.hpp>
+
+#include <iterator>
+#include <memory>
+
+namespace DeviceAPI {
+namespace Contact {
+namespace EBook {
+
+// Signal callback. Specializations will handle varying number of parameters.
+template<class S> struct GObjectSignalHandler {
+    // static void handler();
+    // No specialization defined for the requested function prototype.
+};
+
+template<> struct GObjectSignalHandler<void ()> {
+    static void handler(gpointer data) throw () {
+        (*reinterpret_cast< boost::function<void ()> *>(data))();
+    }
+};
+template<class A1> struct GObjectSignalHandler<void (A1)> {
+    static void handler(A1 a1, gpointer data) throw () {
+        (*reinterpret_cast< boost::function<void (A1)> *>(data))(a1);
+    }
+};
+template<class A1, class A2> struct GObjectSignalHandler<void (A1, A2)> {
+    static void handler(A1 a1, A2 a2, gpointer data) throw () {
+        (*reinterpret_cast< boost::function<void (A1, A2)> *>(data))(a1, a2);
+    }
+};
+template<class A1, class A2, class A3> struct GObjectSignalHandler<void (A1, A2, A3)> {
+    static void handler(A1 a1, A2 a2, A3 a3, gpointer data) throw () {
+        (*reinterpret_cast< boost::function<void (A1, A2, A3)> *>(data))(a1, a2, a3);
+    }
+};
+template<class A1, class A2, class A3, class A4> struct GObjectSignalHandler<void (A1, A2, A3, A4)> {
+    static void handler(A1 a1, A2 a2, A3 a3, A4 a4, gpointer data) throw () {
+        (*reinterpret_cast< boost::function<void (A1, A2, A3, A4)> *>(data))(a1, a2, a3, a4);
+    }
+};
+template<class A1, class A2, class A3, class A4, class A5> struct GObjectSignalHandler<void (A1, A2, A3, A4, A5)> {
+    static void handler(A1 a1, A2 a2, A3 a3, A4 a4, A5 a5, gpointer data) throw () {
+        (*reinterpret_cast< boost::function<void (A1, A2, A3, A4, A5)> *>(data))(a1, a2, a3, a4, a5);
+    }
+};
+template<class A1, class A2, class A3, class A4, class A5, class A6> struct GObjectSignalHandler<void (A1, A2, A3, A4, A5, A6)> {
+    static void handler(A1 a1, A2 a2, A3 a3, A4 a4, A5 a5, A6 a6, gpointer data) throw () {
+        (*reinterpret_cast< boost::function<void (A1, A2, A3, A4, A5, A6)> *>(data))(a1, a2, a3, a4, a5, a6);
+    }
+};
+template<class A1, class A2, class A3, class A4, class A5, class A6, class A7> struct GObjectSignalHandler<void (A1, A2, A3, A4, A5, A6, A7)> {
+    static void handler(A1 a1, A2 a2, A3 a3, A4 a4, A5 a5, A6 a6, A7 a7, gpointer data) throw () {
+        (*reinterpret_cast< boost::function<void (A1, A2, A3, A4, A5, A6, A7)> *>(data))(a1, a2, a3, a4, a5, a6, a7);
+    }
+};
+template<class A1, class A2, class A3, class A4, class A5, class A6, class A7, class A8> struct GObjectSignalHandler<void (A1, A2, A3, A4, A5, A6, A7, A8)> {
+    static void handler(A1 a1, A2 a2, A3 a3, A4 a4, A5 a5, A6 a6, A7 a7, A8 a8, gpointer data) throw () {
+        (*reinterpret_cast< boost::function<void (A1, A2, A3, A4, A5, A6, A7, A8)> *>(data))(a1, a2, a3, a4, a5, a6, a7, a8);
+    }
+};
+template<class A1, class A2, class A3, class A4, class A5, class A6, class A7, class A8, class A9> struct GObjectSignalHandler<void (A1, A2, A3, A4, A5, A6, A7, A8, A9)> {
+    static void handler(A1 a1, A2 a2, A3 a3, A4 a4, A5 a5, A6 a6, A7 a7, A8 a8, A9 a9, gpointer data) throw () {
+        (*reinterpret_cast< boost::function<void (A1, A2, A3, A4, A5, A6, A7, A8, A9)> *>(data))(a1, a2, a3, a4, a5, a6, a7, a8, a9);
+    }
+};
+
+enum RefOwnership
+{
+    TRANSFER_REF = false, /**<
+                           * Create new smart pointer which steals an existing reference without
+                           * increasing the reference count of the object.
+                           */
+    ADD_REF = true        /**<
+                           * Create new smart pointer which increases the reference count when
+                           * storing the pointer to the object.
+                           */
+};
+
+
+template<class C> class TrackGObject : public boost::intrusive_ptr<C> {
+    typedef boost::intrusive_ptr<C> Base_t;
+
+    // Frees the instance of boost::function which was allocated
+    // by connectSignal.
+    template<class S> static void signalDestroy(gpointer data, GClosure *closure) throw () {
+        delete reinterpret_cast< boost::function<void ()> *>(data);
+    }
+
+ public:
+    typedef C PlainC_t;
+
+    TrackGObject(C *ptr, RefOwnership ownership) : Base_t(ptr, (bool)ownership) {}
+    TrackGObject() {}
+    TrackGObject(const TrackGObject &other) : Base_t(other) {}
+    operator C * () const { return Base_t::get(); }
+    operator bool () const { return Base_t::get() != NULL; }
+    C * ref() const { return static_cast<C *>(g_object_ref(Base_t::get())); }
+    void take(C *ptr) { *this = steal(ptr); }
+
+    static  TrackGObject steal(C *ptr) { return TrackGObject(ptr, TRANSFER_REF); }
+
+    template<class S> guint connectSignal(const char *signal,
+                                          const boost::function<S> &callback) {
+        return g_signal_connect_data(Base_t::get(), signal,
+                                     G_CALLBACK(&GObjectSignalHandler<S>::handler),
+                                     new boost::function<S>(callback),
+                                     &signalDestroy<S>,
+                                     GConnectFlags(0));
+    }
+    void disconnectSignal(guint handlerID) {
+        g_signal_handler_disconnect(static_cast<gpointer>(Base_t::get()),
+                                    handlerID);
+    }
+};
+
+template<class C> class StealGObject : public TrackGObject<C> {
+ public:
+    StealGObject(C *ptr) : TrackGObject<C>(ptr, TRANSFER_REF) {}
+    StealGObject() {}
+    StealGObject(const StealGObject &other) : TrackGObject<C>(other) {}
+};
+
+template<class C> class TrackGLib : public boost::intrusive_ptr<C> {
+    typedef boost::intrusive_ptr<C> Base_t;
+
+ public:
+    typedef C PlainC_t;
+
+    TrackGLib(C *ptr, RefOwnership ownership) : Base_t(ptr, (bool)ownership) {}
+    TrackGLib() {}
+    TrackGLib(const TrackGLib &other) : Base_t(other) {}
+    operator C * () const { return Base_t::get(); }
+    operator bool () const { return Base_t::get() != NULL; }
+    C * ref() const { return static_cast<C *>(g_object_ref(Base_t::get())); }
+    void take(C *ptr) { *this = steal(ptr); }
+
+    static  TrackGLib steal(C *ptr) { return TrackGLib(ptr, TRANSFER_REF); }
+};
+
+template<class C> class StealGLib : public TrackGLib<C> {
+ public:
+    StealGLib(C *ptr) : TrackGLib<C>(ptr, TRANSFER_REF) {}
+    StealGLib() {}
+    StealGLib(const StealGLib &other) : TrackGLib<C>(other) {}
+};
+
+/**
+ * Defines a shared pointer for a GObject-based type, with intrusive
+ * reference counting. Use inside DeviceAPI::Contact::EBook namespace
+ * This is necessary because some functions must be put into the boost
+ * namespace. The type itself is *inside* namespace.
+ *
+ * connectSignal() connects a GObject signal to a boost::function with
+ * the function signature S. Returns the handler ID, which can be
+ * passed to g_signal_handler_disconnect() to remove the connection.
+ *
+ * Example:
+ * SE_GOBJECT_TYPE(GFile)
+ * SE_GOBJECT_TYPE(GObject)
+ *
+ *   // reference normally increased during construction,
+ *   // steal() avoids that
+ *   GFileCXX filecxx = GFileCXX::steal(g_file_new_for_path("foo"));
+ *   GFile *filec = filecxx.get(); // does not increase reference count
+ *   // file freed here as filecxx gets destroyed
+ *
+ * GObjectCXX object(...);
+ * // Define signature explicitly because it cannot be guessed from
+ * // boost::bind() result.
+ * object.connectSignal<void (GObject *gobject, GParamSpec *pspec)>("notify",
+ *                                                                  boost::bind(...));
+ * // Signature is taken from boost::function parameter.
+ * guint handlerID =
+ *     object.connectSignal("notify",
+ *                          boost::function<void (GObject *, GParamSpec *)>(boost::bind(...)));
+ * object.disconnectSignal(handlerID);
+ * SE_END_CXX
+ */
+#define SE_GOBJECT_TYPE(_x) \
+    } } } \
+    void inline intrusive_ptr_add_ref(_x *ptr) { g_object_ref(ptr); } \
+    void inline intrusive_ptr_release(_x *ptr) { g_object_unref(ptr); } \
+    namespace DeviceAPI { namespace Contact { namespace EBook { \
+    typedef TrackGObject<_x> _x ## CXX; \
+    typedef StealGObject<_x> _x ## StealCXX; \
+
+/**
+ * Defines a CXX smart pointer similar to SE_GOBJECT_TYPE,
+ * but for types which have their own _ref and _unref
+ * calls.
+ *
+ * Example:
+ * SE_GLIB_TYPE(GMainLoop, g_main_loop)
+ */
+#define SE_GLIB_TYPE(_x, _func_prefix) \
+    } } } \
+    void inline intrusive_ptr_add_ref(_x *ptr) { _func_prefix ## _ref(ptr); } \
+    void inline intrusive_ptr_release(_x *ptr) { _func_prefix ## _unref(ptr); } \
+    namespace DeviceAPI { namespace Contact { namespace EBook { \
+    typedef TrackGLib<_x> _x ## CXX; \
+    typedef StealGLib<_x> _x ## StealCXX; \
+
+/**
+ * Wraps GError. Where a GError** is expected, simply pass
+ * a GErrorCXX instance.
+ */
+struct GErrorCXX {
+    GError *m_gerror;
+
+    /** empty error, NULL pointer */
+    GErrorCXX() : m_gerror(NULL) {}
+
+    /** copies error content */
+    GErrorCXX(const GErrorCXX &other) : m_gerror(g_error_copy(other.m_gerror)) {}
+    GErrorCXX &operator =(const GErrorCXX &other) {
+        if (m_gerror != other.m_gerror) {
+            if (m_gerror) {
+                g_clear_error(&m_gerror);
+            }
+            if (other.m_gerror) {
+                m_gerror = g_error_copy(other.m_gerror);
+            }
+        }
+        return *this;
+    }
+    GErrorCXX &operator =(const GError* err) {
+        if (err != m_gerror) {
+            if (m_gerror) {
+                g_clear_error(&m_gerror);
+            }
+            if (err) {
+                m_gerror = g_error_copy(err);
+            }
+        }
+        return *this;
+    }
+
+    /** takes over ownership */
+    void take (GError *err) {
+        if (err != m_gerror) {
+            if (m_gerror) {
+                g_clear_error(&m_gerror);
+            }
+            m_gerror = err;
+        }
+    }
+
+    /** For convenient access to GError members (message, domain, ...) */
+    const GError * operator-> () const { return m_gerror; }
+
+    /**
+     * For passing to C functions. They must not free the GError,
+     * because GErrorCXX retains ownership.
+     */
+    operator const GError * () const { return m_gerror; }
+
+    /** error description, with fallback if not set (not expected, so not localized) */
+    operator const char * () const { return msg(); }
+    const char *msg() const { return m_gerror ? m_gerror->message : "<<no error>>"; }
+
+    /** clear error */
+    ~GErrorCXX() { g_clear_error(&m_gerror); }
+
+    /** clear error if any is set */
+    void clear() { g_clear_error(&m_gerror); }
+
+    /** transfer ownership of error back to caller */
+    GError *release() { GError *gerror = m_gerror; m_gerror = NULL; return gerror; }
+
+    /** checks whether the current error is the one passed as parameters */
+    bool matches(GQuark domain, gint code) { return g_error_matches(m_gerror, domain, code); }
+
+    /**
+     * Use this when passing GErrorCXX instance to C functions which need to set it.
+     * Make sure the pointer isn't set yet (new GErrorCXX instance, reset if
+     * an error was encountered before) or the GNOME functions will complain
+     * when overwriting the existing error.
+     */
+    operator GError ** () { return &m_gerror; }
+
+    /** true if error set */
+    operator bool () { return m_gerror != NULL; }
+
+    /**
+     * always throws an exception, including information from GError if available:
+     * <action>: <error message>|failure
+     */
+    void throwError(const std::string &action);
+    static void throwError(const std::string &action, const GError *err);
+};
+
+template<class T> void NoopDestructor(T *) {}
+template<class T> void GObjectDestructor(T *ptr) { g_object_unref(ptr); }
+template<class T> void GFreeDestructor(T *ptr) { g_free(static_cast<void *>(ptr)); }
+
+/**
+ * Wraps a G[S]List of pointers to a specific type.
+ * Can be used with boost::FOREACH and provides forward iterators
+ * (two-way iterators and reverse iterators also possible, but not implemented).
+ * Frees the list and optionally (not turned on by default) also frees
+ * the data contained in it, using the provided destructor class.
+ * Use GObjectDestructor for GObject instances.
+ *
+ * Can be swapped, but not copied.
+ *
+ * @param T    the type of the instances pointed to inside the list
+ * @param L    GList or GSList
+ * @param D    destructor function freeing a T instance
+ * @param d    destroy list itself (D still gets called even if false)
+ */
+ template< class T, class L, void (*D)(T*) = NoopDestructor<T>, bool d = true> struct GListCXX : boost::noncopyable {
+    L *m_list;
+
+    static void listFree(GSList *l) { g_slist_free(l); }
+    static void listFree(GList *l) { g_list_free(l); }
+
+    static GSList *listPrepend(GSList *list, T *entry) { return g_slist_prepend(list, (gpointer)entry); }
+    static GList *listPrepend(GList *list, T *entry) { return g_list_prepend(list, (gpointer)entry); }
+
+    static GSList *listAppend(GSList *list, T *entry) { return g_slist_append(list, (gpointer)entry); }
+    static GList *listAppend(GList *list, T *entry) { return g_list_append(list, (gpointer)entry); }
+
+ public:
+    typedef T * value_type;
+
+    /** by default initialize an empty list; if parameter is not NULL,
+        owership is transferred to the new instance of GListCXX */
+    GListCXX(L *list = NULL) : m_list(list) {}
+
+    /** free list */
+    ~GListCXX() { clear(); }
+
+    /** free old content, take owership of new one */
+    void reset(L *list = NULL) {
+        clear();
+        m_list = list;
+    }
+
+    /** relinquish ownership of content */
+    L *release() { L *list = m_list; m_list = NULL; return list; }
+
+    /** swap content with other list */
+    void swap(GListCXX &other) { std::swap(m_list, other.m_list); }
+
+    bool empty() { return m_list == NULL; }
+    operator bool () { return !empty(); }
+
+    /** free list */
+    void clear() {
+        BOOST_FOREACH(T *entry, *this) {
+            D(entry);
+        }
+       if (d) {
+               listFree(m_list);
+       }
+        m_list = NULL;
+    }
+
+    /**
+     * Use this when passing GListCXX instance to C functions which need to set it.
+     * Make sure the pointer isn't set yet (new GListCXX instance or cleared).
+     */
+    operator L ** () { return &m_list; }
+
+    /**
+     * Cast to plain G[S]List, for use in functions which do not modify the list.
+     */
+    operator L * () { return m_list; }
+
+    class iterator : public std::iterator<std::forward_iterator_tag, T *> {
+        L *m_entry;
+    public:
+        iterator(L *list = NULL) : m_entry(list) {}
+        iterator(const iterator &other) : m_entry(other.m_entry) {}
+        /**
+         * boost::foreach needs a reference as return code here,
+         * which forces us to do type casting on the address of the void * pointer,
+         * then dereference the pointer. The reason is that typecasting the
+         * pointer value directly yields an rvalue, which can't be used to initialize
+         * the reference return value.
+         */
+        T * &operator -> () const { return *getEntryPtr(); }
+        T * &operator * () const { return *getEntryPtr(); }
+        iterator & operator ++ () { m_entry = m_entry->next; return *this; }
+        iterator operator ++ (int) { return iterator(m_entry->next); }
+        bool operator == (const iterator &other) { return m_entry == other.m_entry; }
+        bool operator != (const iterator &other) { return m_entry != other.m_entry; }
+
+    private:
+        /**
+         * Used above, necessary to hide the fact that we do type
+         * casting tricks. Otherwise the compiler will complain about
+         * *(T **)&m_entry->data with "dereferencing type-punned
+         * pointer will break strict-aliasing rules".
+         *
+         * That warning is about breaking assumptions that the compiler
+         * uses for optimizations. The hope is that those optimzations
+         * aren't done here, and/or are disabled by using a function.
+         */
+        T** getEntryPtr() const { return (T **)&m_entry->data; }
+    };
+    iterator begin() { return iterator(m_list); }
+    iterator end() { return iterator(NULL); }
+
+    class const_iterator : public std::iterator<std::forward_iterator_tag, T *> {
+        L *m_entry;
+        T *m_value;
+
+    public:
+        const_iterator(L *list = NULL) : m_entry(list) {}
+        const_iterator(const const_iterator &other) : m_entry(other.m_entry) {}
+        T * &operator -> () const { return *getEntryPtr(); }
+        T * &operator * () const { return *getEntryPtr(); }
+        const_iterator & operator ++ () { m_entry = m_entry->next; return *this; }
+        const_iterator operator ++ (int) { return const_iterator(m_entry->next); }
+        bool operator == (const const_iterator &other) { return m_entry == other.m_entry; }
+        bool operator != (const const_iterator &other) { return m_entry != other.m_entry; }
+
+    private:
+        T** getEntryPtr() const { return (T **)&m_entry->data; }
+    };
+
+    const_iterator begin() const { return const_iterator(m_list); }
+    const_iterator end() const { return const_iterator(NULL); }
+
+    void push_back(T *entry) { m_list = listAppend(m_list, entry); }
+    void push_front(T *entry) { m_list = listPrepend(m_list, entry); }
+};
+
+/** use this for a list which owns the strings it points to */
+typedef GListCXX<char, GList, GFreeDestructor<char> > GStringListFreeCXX;
+/** use this for a list which does not own the strings it points to */
+typedef GListCXX<char, GList> GStringListNoFreeCXX;
+
+/**
+ * Wraps a C gchar array and takes care of freeing the memory.
+ */
+class PlainGStr : public boost::shared_ptr<gchar>
+{
+    public:
+        PlainGStr() {}
+        PlainGStr(gchar *str) : boost::shared_ptr<char>(str, g_free) {}
+        PlainGStr(const PlainGStr &other) : boost::shared_ptr<gchar>(other) {}
+        PlainGStr(const boost::shared_ptr<gchar> &other) : boost::shared_ptr<gchar>(other) {}
+        // can return NULL
+       gchar *get() const { return (*this) ? &**this : NULL; }
+        operator gchar *() const { return get(); }
+
+       // Never NULL.
+        const gchar *c_str() const { const gchar *res = get(); return res ? res : ""; }
+
+       // Disambiguate bool operator.
+       operator bool () const { return (bool)*(boost::shared_ptr<gchar> *)this; }
+};
+
+/**
+ * Wraps a glib string array, frees with g_strfreev().
+ */
+class PlainGStrArray : public boost::shared_ptr<gchar *>
+{
+    public:
+        PlainGStrArray() {}
+        PlainGStrArray(gchar **array) : boost::shared_ptr<char *>(array, g_strfreev) {}
+        PlainGStrArray(const PlainGStrArray &other) : boost::shared_ptr<char *>(other) {}
+        operator gchar * const *() const { return &**this; }
+        gchar * &at(size_t index) { return get()[index]; }
+ private:
+        // Hide this operator because boost::shared_ptr has problems with it,
+        // probably because of missing traits for a pointer type. Instead use
+        // at().
+        gchar * operator[] (size_t index);
+};
+
+} // EBook
+} // Contact
+} // DeviceAPI
+
+#endif // _PLATFORM_CONTACT_CONTACTS2EBOOK_CONTACTS_H_
diff --git a/src/Contact/contacts2ebook/README b/src/Contact/contacts2ebook/README
new file mode 100644 (file)
index 0000000..26aa3c9
--- /dev/null
@@ -0,0 +1,119 @@
+Tizen Contact API using Evolution Data Server (EDS)
+===================================================
+
+Implementation
+--------------
+
+The implementation tries to reuse as much of the existing code as
+possible, for two reason:
+* stay as close as possible to the original semantic; in particular,
+  the JavaScript binding is identical
+* avoid forking
+
+As often as possible, constructs like contacts_contact_h in the
+contacts service are reimplemented to avoid ifdefs. A custom
+"contacts.h" in this directory provides that.
+
+The new code uses smart handles for plain C objects and resources,
+using a boost and template based C++ binding for glib which originates
+in the SyncEvolution project. Therefore it is automatically exception
+safe, in contrast to the old code, which relied on manual resource
+tracking.
+
+Because contacts_contact_h and contacts_list_h are no longer plain
+pointers, some code in the plugin which only worked for plain pointers had
+to be changed so that it works for both plain pointers and smart pointers:
+* contacts_list_h contacts = NULL => contacts_list_h contacts(NULL)
+* if (contact_record == NULL) => if (!contact_record)
+
+TODO: #define CONTACTS_ERROR_NONE 0 + remove ifdef in ResultCallback
+TODO: to vCard 2.1
+
+However, several concepts are too different to be handled without ifdefs:
+* access to contact properties
+* IDs: they are strings in EDS, integers in contacts service; to get
+  tests running which assumed "0" as ID of the system address book,
+  "0" is mapped to EDS' "system-address-book" by the plugin. The tests
+  are incorrect in that regard, but it is better to stay closer to the
+  original implementation if possible because apps might make similar
+  assumptions.
+
+Sometimes variable instantiation had to moved into the ifdef sections
+to avoid compiler warnings when these variables were not in use.
+
+Searching is implemented using a different philosophy. With contacts
+service, the plugin implements some of the semantic itself by running
+multiple queries and combining the results. With EDS, the JavaScript
+query is translated into a single database query. This is faster, but
+less accurate.
+
+The EDS version of the plugin supports dynamic creation and deletion
+of address books, in contrast to the contacts service one where the
+list of address books iss only populated once when the JavaScript app
+starts up.
+
+The display name of a contact is hard-coded to the EDS file-as
+extended property (usually not set), full name = "Last name, first
+name" (unless explicity set via FN when importing a contact), org unit
+or first email address. Sorting is also hard-coded, however it is
+limited to last name and first name as tie-breaker because the display
+name is not (currently) available as key for sorting.
+
+TODO (?): add E_CONTACT_NAME_OR_ORG as summary field in EDS and use it
+for sorting.
+
+Usage
+-----
+
+The choice between EDS and contacts service must be made at compile
+time. Invoke cmake with -DWITH_EBOOK=YES to enable EDS. A profile must
+set the bcond wrt_option_eds to enable EDS. Default is always contacts
+service.
+
+Debugging
+---------
+
+Enable the "#if 0 // DEBUG-CONTACTS" section in ContactsSvsWrapper.cpp
+while compiling (has to be done by editing the source), then create
+/tmp/debug-contacts to cause the plugin to wait 10 seconds when
+starting up. /tmp/contacts-wrt.pid contains the process ID of the
+waiting process.
+
+Use for example like this:
+$ touch /tmp/debug-contacts && rm -f /tmp/contacts-wrt.pid
+$ <start test> &
+$ while [ ! -e /tmp/contacts-wrt.pid ]; do : ; done; gdb -p `cat /tmp/contacts-wrt.pid`
+
+Limitations
+-----------
+
+The "Person" and "unified address book" concept and all methods
+related to them in the "tizen.contact" API is not supported. Contacts
+have a fake personId, but it cannot be used for anything.
+
+Contact groups are not supported.
+
+The "EXACTLY" match mode is not supported and silently executed like a
+case insensitive FULLSTRING search. EDS implements that operation and
+the suffix/prefix searches also accent insensitive.
+
+Value range matches and non-string value matches are not supported.
+
+Searching for address values is not supported.
+
+Only a single birthday is support, generic anniversaries are not.
+
+Phonetic names are not supported.
+
+Org information is limited to one company, unit, title, role and
+assistant.
+
+Only one note is supported.
+
+URLs and nicknames are not supported. They could be mapped to certain
+EDS vCard extensions.
+
+A contact cannot be marked as favorite. There is no ringtone property.
+
+When a JavaScript app tries to store unsupported values, storing
+silently drops the unsupported values.
diff --git a/src/Contact/contacts2ebook/contacts.h b/src/Contact/contacts2ebook/contacts.h
new file mode 100644 (file)
index 0000000..cedb2d8
--- /dev/null
@@ -0,0 +1,160 @@
+//
+// Tizen Web Device API
+// Copyright (c) 2013 Intel
+//
+// Licensed under the Apache License, Version 2.0 (the License);
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+//
+// This file minimizes ifdefs in the rest of the code by providing:
+// - a replacement for the original contacts.h from contacts-service2
+// - a mapping from some symbols in that file to replacements
+//
+// This file only gets included when compiling against libebook instead
+// of contacts-service2.
+
+#ifndef _PLATFORM_CONTACT_CONTACTS2EBOOK_CONTACTS_H_
+#define _PLATFORM_CONTACT_CONTACTS2EBOOK_CONTACTS_H_
+
+#include <libebook/libebook.h>
+#include <libedataserver/libedataserver.h>
+#include <glib.h>
+
+#include <dpl/noncopyable.h>
+
+#include "GLibSupport.h"
+
+namespace DeviceAPI {
+namespace Contact {
+namespace EBook {
+
+SE_GOBJECT_TYPE(EContact)
+SE_GOBJECT_TYPE(EBookClient)
+SE_GLIB_TYPE(EBookQuery, e_book_query)
+SE_GOBJECT_TYPE(EBookClientView)
+SE_GOBJECT_TYPE(ESource)
+SE_GOBJECT_TYPE(ESourceRegistry)
+SE_GOBJECT_TYPE(EBookClientCursor)
+
+typedef GListCXX<char, GSList, GFreeDestructor<char> > UIDList;
+typedef GListCXX<ESource, GList, GObjectDestructor<ESource> >ESourceList;
+
+enum {
+       CONTACTS_ERROR_NONE
+};
+
+enum contacts_match_str_flag_e {
+       CONTACTS_MATCH_EXISTS,
+       CONTACTS_MATCH_EXACTLY,
+       CONTACTS_MATCH_FULLSTRING,
+       CONTACTS_MATCH_CONTAINS,
+       CONTACTS_MATCH_STARTSWITH,
+       CONTACTS_MATCH_ENDSWITH
+};
+
+enum contacts_match_int_flag_e {
+       CONTACTS_MATCH_GREATER_THAN_OR_EQUAL,
+       CONTACTS_MATCH_LESS_THAN_OR_EQUAL,
+       CONTACTS_MATCH_EQUAL
+};
+
+template <class T> class Handle : public T
+{
+ public:
+       // For contacts_record_h contacts_record = NULL
+       Handle(void * = NULL) {}
+       Handle(typename T::PlainC_t *object, RefOwnership ownership) : T(object, ownership) {}
+       Handle(const Handle &other) : T(other) {}
+};
+
+
+class ContactsListHandle
+{
+};
+
+class ContactsQueryHandle
+{
+};
+
+class ContactsFilterHandle
+{
+};
+
+typedef Handle<EContactCXX> contacts_record_h;
+static inline void contacts_record_destroy(contacts_record_h &handle, bool) { handle.reset(); }
+
+typedef GListCXX<EContact, GSList, GObjectDestructor<EContact> > contacts_list_h;
+
+static inline int contacts_list_create(contacts_list_h *list) { return CONTACTS_ERROR_NONE; }
+static inline int contacts_list_destroy(contacts_list_h &list, bool) { list.clear(); return CONTACTS_ERROR_NONE; }
+static inline int contacts_list_add(contacts_list_h &list, const contacts_record_h &contact) { list.push_front((EContact *)g_object_ref(contact)); return CONTACTS_ERROR_NONE; }
+
+
+// Helper C++ code for type-safe access to EContact fields.
+template<EContactField field> struct EContactTraits;
+struct EContactStringType {
+       typedef char type;
+       static void free(char *ptr) { g_free(ptr); }
+};
+struct EContactDateType {
+       typedef EContactDate type;
+       static void free(EContactDate *ptr) { e_contact_date_free(ptr); }
+};
+template<> struct EContactTraits<E_CONTACT_REV> : public EContactStringType {};
+template<> struct EContactTraits<E_CONTACT_UID> : public EContactStringType {};
+template<> struct EContactTraits<E_CONTACT_BOOK_UID> : public EContactStringType {};
+template<> struct EContactTraits<E_CONTACT_NAME_OR_ORG> : public EContactStringType {};
+template<> struct EContactTraits<E_CONTACT_ORG> : public EContactStringType {};
+template<> struct EContactTraits<E_CONTACT_ORG_UNIT> : public EContactStringType {};
+template<> struct EContactTraits<E_CONTACT_OFFICE> : public EContactStringType {};
+template<> struct EContactTraits<E_CONTACT_TITLE> : public EContactStringType {};
+template<> struct EContactTraits<E_CONTACT_ROLE> : public EContactStringType {};
+template<> struct EContactTraits<E_CONTACT_MANAGER> : public EContactStringType {};
+template<> struct EContactTraits<E_CONTACT_ASSISTANT> : public EContactStringType {};
+template<> struct EContactTraits<E_CONTACT_NOTE> : public EContactStringType {};
+template<> struct EContactTraits<E_CONTACT_PHOTO> {
+       typedef EContactPhoto type;
+       static void free(EContactPhoto *ptr) { e_contact_photo_free(ptr); }
+};
+template<> struct EContactTraits<E_CONTACT_NAME> {
+       typedef EContactName type;
+       static void free(EContactName *ptr) { e_contact_name_free(ptr); }
+};
+template<> struct EContactTraits<E_CONTACT_BIRTH_DATE> : public EContactDateType {};
+template<> struct EContactTraits<E_CONTACT_ANNIVERSARY> : public EContactDateType {};
+template<EContactField field> struct EContactFieldCXX {
+       static boost::shared_ptr<typename EContactTraits<field>::type> get(EContact *contact) {
+               return boost::shared_ptr<typename EContactTraits<field>::type>(static_cast<typename EContactTraits<field>::type *>(e_contact_get(contact, field)),
+                                              free);
+       }
+       static void set(EContact *contact, const typename EContactTraits<field>::type *value) {
+               e_contact_set(contact, field, value);
+       }
+       static void setString(EContact *contact, const std::string &value, bool isSet) {
+               set(contact, isSet ? value.c_str() : NULL);
+       }
+};
+
+
+typedef EBookQueryCXX contacts_query_h;
+
+// not supported
+typedef void * contacts_filter_h;
+
+} // EBook
+} // Contact
+} // DeviceAPI
+
+using namespace DeviceAPI::Contact::EBook;
+
+#endif // _PLATFORM_CONTACT_CONTACTS2EBOOK_CONTACTS_H_