From b74fb248104c8caa640277f1a10cdbdd272a35ab Mon Sep 17 00:00:00 2001 From: Patrick Ohly Date: Tue, 12 Nov 2013 16:56:48 +0100 Subject: [PATCH] implement Contacts API using Evolution Data Server (TIVI-1407) 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 --- CMakeLists.txt | 6 + packaging/wrt-plugins-tizen.changes | 3 + packaging/wrt-plugins-tizen.spec | 11 + src/Contact/AddressBook.cpp | 595 +++++++++++++++++++---- src/Contact/AddressBook.h | 74 ++- src/Contact/CMakeLists.txt | 7 +- src/Contact/Contact.cpp | 40 +- src/Contact/ContactManager.cpp | 73 ++- src/Contact/ContactObjectA2PConverter.cpp | 239 ++++++++- src/Contact/ContactObjectA2PConverter.h | 11 +- src/Contact/ContactObjectP2AConverter.cpp | 452 ++++++++++++++++- src/Contact/ContactObjectP2AConverter.h | 16 + src/Contact/ContactSearchEngine.cpp | 352 +++++++++++--- src/Contact/ContactSearchEngine.h | 38 +- src/Contact/ContactsSvcChangeListenerManager.cpp | 6 + src/Contact/ContactsSvcChangeListenerManager.h | 11 + src/Contact/ContactsSvcObjectConverter.cpp | 14 + src/Contact/ContactsSvcWrapper.cpp | 110 ++++- src/Contact/ContactsSvcWrapper.h | 12 + src/Contact/IAddressBook.h | 2 +- src/Contact/JSAddressBook.cpp | 13 +- src/Contact/Person.cpp | 31 +- src/Contact/PersonSearchEngine.cpp | 4 + src/Contact/PersonSearchEngine.h | 4 + src/Contact/contacts2ebook/GLibSupport.h | 515 ++++++++++++++++++++ src/Contact/contacts2ebook/README | 119 +++++ src/Contact/contacts2ebook/contacts.h | 160 ++++++ 27 files changed, 2713 insertions(+), 205 deletions(-) create mode 100644 src/Contact/contacts2ebook/GLibSupport.h create mode 100644 src/Contact/contacts2ebook/README create mode 100644 src/Contact/contacts2ebook/contacts.h diff --git a/CMakeLists.txt b/CMakeLists.txt index 80baa2d..5afd1bf 100755 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -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 ) diff --git a/packaging/wrt-plugins-tizen.changes b/packaging/wrt-plugins-tizen.changes index 7d0754c..fa3c13d 100644 --- a/packaging/wrt-plugins-tizen.changes +++ b/packaging/wrt-plugins-tizen.changes @@ -1,3 +1,6 @@ +* Tue Nov 19 2013 Patrick Ohly accepted/tizen/20131118.182136@e0defdb +- implement Contacts API using Evolution Data Server (TIVI-1407) + * Tue Nov 19 2013 Rusty Lynch 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. diff --git a/packaging/wrt-plugins-tizen.spec b/packaging/wrt-plugins-tizen.spec index 5392c5e..6149055 100755 --- a/packaging/wrt-plugins-tizen.spec +++ b/packaging/wrt-plugins-tizen.spec @@ -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} diff --git a/src/Contact/AddressBook.cpp b/src/Contact/AddressBook.cpp index b447703..ffa3e1f 100755 --- a/src/Contact/AddressBook.cpp +++ b/src/Contact/AddressBook.cpp @@ -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("objects-added", boost::bind(&AddressBook::onContactsEDSContactsAddedOrUpdated, + this, + _2, + &AddressBook::onContactsSvcContactsAdded)); + m_view.connectSignal("objects-modified", boost::bind(&AddressBook::onContactsEDSContactsAddedOrUpdated, + this, + _2, + &AddressBook::onContactsSvcContactsUpdated)); + m_view.connectSignal("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 newContactT = DPL::StaticPointerCast(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 contactT = DPL::StaticPointerCast(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 newContactT = DPL::StaticPointerCast(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, 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, 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; igetAbstractContact(); } @@ -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::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::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); diff --git a/src/Contact/AddressBook.h b/src/Contact/AddressBook.h index adfc5b0..ffc1ee3 100755 --- a/src/Contact/AddressBook.h +++ b/src/Contact/AddressBook.h @@ -30,6 +30,7 @@ #include #include "IAddressBook.h" #include "IContact.h" +#include #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 AddressBookChangedEmitter; AddressBookChangedEmitter m_addressBookEmitters; @@ -138,14 +155,55 @@ private: typedef std::map 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 { diff --git a/src/Contact/CMakeLists.txt b/src/Contact/CMakeLists.txt index 5dc9cae..647e13b 100755 --- a/src/Contact/CMakeLists.txt +++ b/src/Contact/CMakeLists.txt @@ -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") diff --git a/src/Contact/Contact.cpp b/src/Contact/Contact.cpp index 93e00f5..1bccb56 100644 --- a/src/Contact/Contact.cpp +++ b/src/Contact/Contact.cpp @@ -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) diff --git a/src/Contact/ContactManager.cpp b/src/Contact/ContactManager.cpp index 3dd4aca..fd55345 100755 --- a/src/Contact/ContactManager.cpp +++ b/src/Contact/ContactManager.cpp @@ -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); diff --git a/src/Contact/ContactObjectA2PConverter.cpp b/src/Contact/ContactObjectA2PConverter.cpp index c71d52d..ff9d777 100755 --- a/src/Contact/ContactObjectA2PConverter.cpp +++ b/src/Contact/ContactObjectA2PConverter.cpp @@ -23,6 +23,7 @@ */ #include "ContactObjectA2PConverter.h" +#include "ContactObjectP2AConverter.h" #include #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::set(m_platformContact, NULL); + } else { + EContactPhoto photo; + photo.type = E_CONTACT_PHOTO_TYPE_URI; + string uri = m_abstractContact->getPhotoURI(); + photo.data.uri = const_cast(uri.c_str()); + EContactFieldCXX::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::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(first.c_str()) : NULL; + name.additional = contactName->getMiddleNameIsSet() ? const_cast(middle.c_str()) : NULL; + name.family = contactName->getLastNameIsSet() ? const_cast(last.c_str()) : NULL; + name.prefixes = contactName->getPrefixIsSet() ? const_cast(prefix.c_str()) : NULL; + name.suffixes = contactName->getSuffixIsSet() ? const_cast(suffix.c_str()) : NULL; + EContactFieldCXX::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::set(m_platformContact, NULL); + EContactFieldCXX::set(m_platformContact, NULL); + EContactFieldCXX::set(m_platformContact, NULL); + EContactFieldCXX::set(m_platformContact, NULL); + EContactFieldCXX::set(m_platformContact, NULL); +#endif return; + } ContactOrganizationArray::iterator organizationsIter = organizations->begin(); for(; organizationsIter != organizations->end(); organizationsIter++) { ContactOrganizationPtr organization = *organizationsIter; +#ifdef FEATURE_EBOOK + EContactFieldCXX::setString(m_platformContact, organization->getName(), organization->getNameIsSet()); + EContactFieldCXX::setString(m_platformContact, organization->getDepartment(), organization->getDepartmentIsSet()); + EContactFieldCXX::setString(m_platformContact, organization->getTitle(), organization->getTitleIsSet()); + EContactFieldCXX::setString(m_platformContact, organization->getRole(), organization->getRoleIsSet()); + EContactFieldCXX::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::set(m_platformContact, NULL); +#endif return; + } StringArray::iterator notesIter = notes->begin(); for(; notesIter != notes->end(); notesIter++) { string note = *notesIter; +#ifdef FEATURE_EBOOK + EContactFieldCXX::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 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 +void importList(contacts_record_h &record, const EArray &array, + const char *property, + const Types *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 *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::set(m_platformContact, &bday); + } else { + EContactFieldCXX::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 diff --git a/src/Contact/ContactObjectA2PConverter.h b/src/Contact/ContactObjectA2PConverter.h index 279eaa2..8a1fd75 100755 --- a/src/Contact/ContactObjectA2PConverter.h +++ b/src/Contact/ContactObjectA2PConverter.h @@ -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; diff --git a/src/Contact/ContactObjectP2AConverter.cpp b/src/Contact/ContactObjectP2AConverter.cpp index 9c498ec..6818736 100755 --- a/src/Contact/ContactObjectP2AConverter.cpp +++ b/src/Contact/ContactObjectP2AConverter.cpp @@ -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::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::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(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 photo = EContactFieldCXX::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::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 name = EContactFieldCXX::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::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::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::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::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::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::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, 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 +void exportList(contacts_record_h &record, Contact *contact, + const char *property, + const Types *types, + T defType, + V *(*getValue)(EVCardAttribute *), + void (Contact::*clearList)(), + EArray (IContact::*getList)() const, + const boost::function 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(NULL); + GListCXX, 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 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(NULL); + GListCXX, false> params(e_vcard_attribute_get_params(attribute)); + BOOST_FOREACH (EVCardAttributeParam *param, params) { + for (const Types *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 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 EDSEmailTypes[] = { + { "HOME", CONTACT_EMAIL_TYPE_HOME }, + { "WORK", CONTACT_EMAIL_TYPE_WORK }, + { "MOBILE", CONTACT_EMAIL_TYPE_MOBILE }, + { NULL } +}; + +Types 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(m_abstractContact), + EVC_TEL, EDSTelTypes, CONTACT_PHONE_NUMBER_TYPE_VOICE, + e_vcard_attribute_get_value, + &Contact::resetNumbersJSObj, + &Contact::getPhoneNumbers, + boost::function(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(m_abstractContact), + EVC_EMAIL, EDSEmailTypes, CONTACT_EMAIL_TYPE_WORK, + e_vcard_attribute_get_value, + &Contact::resetEmailsJSObj, + &Contact::getEmails, + boost::function(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 bday = EContactFieldCXX::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(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(m_abstractContact), + EVC_ADR, EDSAdrTypes, CONTACT_ADDRESS_TYPE_HOME, + e_vcard_attribute_get_values, + &Contact::resetAddressesJSObj, + &Contact::getAddresses, + boost::function(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 diff --git a/src/Contact/ContactObjectP2AConverter.h b/src/Contact/ContactObjectP2AConverter.h index ffb3f2f..f4f894b 100755 --- a/src/Contact/ContactObjectP2AConverter.h +++ b/src/Contact/ContactObjectP2AConverter.h @@ -33,12 +33,25 @@ namespace DeviceAPI { namespace Contact { +#ifdef FEATURE_EBOOK +template struct Types { const char *typeString; T enumVal; }; +extern Types EDSTelTypes[]; +extern Types EDSEmailTypes[]; +extern Types 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; diff --git a/src/Contact/ContactSearchEngine.cpp b/src/Contact/ContactSearchEngine.cpp index 23bb9f2..3e02366 100755 --- a/src/Contact/ContactSearchEngine.cpp +++ b/src/Contact/ContactSearchEngine.cpp @@ -35,6 +35,10 @@ #include "ContactUtility.h" #include +#ifdef FEATURE_EBOOK +# include +#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(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 ¤t = m_queries.back(); + EBookQueryCXX composite; + // Temporary array for EDS. + boost::scoped_array 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 ¤t = 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; igetAbstractContact(); } @@ -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 diff --git a/src/Contact/ContactSearchEngine.h b/src/Contact/ContactSearchEngine.h index a9bdc41..0129c17 100755 --- a/src/Contact/ContactSearchEngine.h +++ b/src/Contact/ContactSearchEngine.h @@ -46,7 +46,11 @@ class ContactSearchEngine : public DPL::EnableSharedFromThis { 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 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 ContactIdArray; typedef DPL::SharedPtr ContactIdArrayPtr; @@ -96,19 +114,34 @@ public: typedef std::vector ContactIdSetArray; typedef DPL::SharedPtr 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 CurrentQueries; + typedef std::vector 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 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 ContactSearchEnginePtr; diff --git a/src/Contact/ContactsSvcChangeListenerManager.cpp b/src/Contact/ContactsSvcChangeListenerManager.cpp index 654a797..053d2d3 100755 --- a/src/Contact/ContactsSvcChangeListenerManager.cpp +++ b/src/Contact/ContactsSvcChangeListenerManager.cpp @@ -22,6 +22,10 @@ * @brief */ +#ifdef FEATURE_EBOOK +// Changes have to be watched by each AddressBook individually. +#else + #include "ContactsSvcChangeListenerManager.h" #include #include @@ -643,3 +647,5 @@ void ContactsSvcChangeListenerManager::personsChangedCallback(char* changes) } // Application } // DeviceAPI + +#endif // FEATURE_EBOOK diff --git a/src/Contact/ContactsSvcChangeListenerManager.h b/src/Contact/ContactsSvcChangeListenerManager.h index 1f592b1..98e4234 100755 --- a/src/Contact/ContactsSvcChangeListenerManager.h +++ b/src/Contact/ContactsSvcChangeListenerManager.h @@ -25,6 +25,15 @@ #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 #include #include @@ -131,4 +140,6 @@ typedef DPL::Singleton ContactsSvcChangeListen } // Contact } // DeviceAPI +#endif // FEATURE_EBOOK + #endif // TIZENAPIS_PLATFORM_CONTACT_CONTACT_LISTENER_MANAGER_H_ diff --git a/src/Contact/ContactsSvcObjectConverter.cpp b/src/Contact/ContactsSvcObjectConverter.cpp index 4e34980..03e85e3 100755 --- a/src/Contact/ContactsSvcObjectConverter.cpp +++ b/src/Contact/ContactsSvcObjectConverter.cpp @@ -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 diff --git a/src/Contact/ContactsSvcWrapper.cpp b/src/Contact/ContactsSvcWrapper.cpp index ef7b9ed..b249300 100755 --- a/src/Contact/ContactsSvcWrapper.cpp +++ b/src/Contact/ContactsSvcWrapper.cpp @@ -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("source-added", boost::bind(&ContactsSvcWrapper::addSource, this, _1)); + m_sourceRegistry.connectSignal("source-enabled", boost::bind(&ContactsSvcWrapper::addSource, this, _1)); + m_sourceRegistry.connectSignal("source-removed", boost::bind(&ContactsSvcWrapper::removeSource, this, _1)); + m_sourceRegistry.connectSignal("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 diff --git a/src/Contact/ContactsSvcWrapper.h b/src/Contact/ContactsSvcWrapper.h index 0949dc8..1b0850a 100755 --- a/src/Contact/ContactsSvcWrapper.h +++ b/src/Contact/ContactsSvcWrapper.h @@ -29,6 +29,7 @@ #include #include #include +#include #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 AddressBooks_t; + AddressBooks_t m_addressBooks; +#else AddressBookPtr m_defaultAddressBook; AddressBookPtr m_unifiedAddressBook; AddressBookArrayPtr m_addressBooks; std::map m_idMap; +#endif }; typedef DPL::Singleton ContactsSvcWrapperSingleton; diff --git a/src/Contact/IAddressBook.h b/src/Contact/IAddressBook.h index ff29063..6fffd54 100755 --- a/src/Contact/IAddressBook.h +++ b/src/Contact/IAddressBook.h @@ -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; diff --git a/src/Contact/JSAddressBook.cpp b/src/Contact/JSAddressBook.cpp index e6bd7ed..6df0468 100755 --- a/src/Contact/JSAddressBook.cpp +++ b/src/Contact/JSAddressBook.cpp @@ -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()); diff --git a/src/Contact/Person.cpp b/src/Contact/Person.cpp index 4057872..831222b 100755 --- a/src/Contact/Person.cpp +++ b/src/Contact/Person.cpp @@ -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); } diff --git a/src/Contact/PersonSearchEngine.cpp b/src/Contact/PersonSearchEngine.cpp index fa046cc..c9a4c94 100755 --- a/src/Contact/PersonSearchEngine.cpp +++ b/src/Contact/PersonSearchEngine.cpp @@ -39,6 +39,8 @@ using namespace WrtDeviceApis::Commons; using namespace DeviceAPI::Tizen; using namespace std; +#ifndef FEATURE_EBOOK + map 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 diff --git a/src/Contact/PersonSearchEngine.h b/src/Contact/PersonSearchEngine.h index cdf128b..e43f422 100755 --- a/src/Contact/PersonSearchEngine.h +++ b/src/Contact/PersonSearchEngine.h @@ -40,6 +40,8 @@ namespace DeviceAPI { namespace Contact { +#ifndef FEATURE_EBOOK + class PersonSearchEngine : public DeviceAPI::Tizen::IFilterVisitor, public DPL::EnableSharedFromThis @@ -83,6 +85,8 @@ private: typedef DPL::SharedPtr PersonSearchEnginePtr; +#endif // FEATURE_EBOOK + } // Contact } // DeviceAPI diff --git a/src/Contact/contacts2ebook/GLibSupport.h b/src/Contact/contacts2ebook/GLibSupport.h new file mode 100644 index 0000000..1886b3d --- /dev/null +++ b/src/Contact/contacts2ebook/GLibSupport.h @@ -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 + +#include +#include +#include +#include +#include +#include + +#include +#include + +namespace DeviceAPI { +namespace Contact { +namespace EBook { + +// Signal callback. Specializations will handle varying number of parameters. +template struct GObjectSignalHandler { + // static void handler(); + // No specialization defined for the requested function prototype. +}; + +template<> struct GObjectSignalHandler { + static void handler(gpointer data) throw () { + (*reinterpret_cast< boost::function *>(data))(); + } +}; +template struct GObjectSignalHandler { + static void handler(A1 a1, gpointer data) throw () { + (*reinterpret_cast< boost::function *>(data))(a1); + } +}; +template struct GObjectSignalHandler { + static void handler(A1 a1, A2 a2, gpointer data) throw () { + (*reinterpret_cast< boost::function *>(data))(a1, a2); + } +}; +template struct GObjectSignalHandler { + static void handler(A1 a1, A2 a2, A3 a3, gpointer data) throw () { + (*reinterpret_cast< boost::function *>(data))(a1, a2, a3); + } +}; +template struct GObjectSignalHandler { + static void handler(A1 a1, A2 a2, A3 a3, A4 a4, gpointer data) throw () { + (*reinterpret_cast< boost::function *>(data))(a1, a2, a3, a4); + } +}; +template struct GObjectSignalHandler { + static void handler(A1 a1, A2 a2, A3 a3, A4 a4, A5 a5, gpointer data) throw () { + (*reinterpret_cast< boost::function *>(data))(a1, a2, a3, a4, a5); + } +}; +template struct GObjectSignalHandler { + static void handler(A1 a1, A2 a2, A3 a3, A4 a4, A5 a5, A6 a6, gpointer data) throw () { + (*reinterpret_cast< boost::function *>(data))(a1, a2, a3, a4, a5, a6); + } +}; +template struct GObjectSignalHandler { + static void handler(A1 a1, A2 a2, A3 a3, A4 a4, A5 a5, A6 a6, A7 a7, gpointer data) throw () { + (*reinterpret_cast< boost::function *>(data))(a1, a2, a3, a4, a5, a6, a7); + } +}; +template struct GObjectSignalHandler { + 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 *>(data))(a1, a2, a3, a4, a5, a6, a7, a8); + } +}; +template struct GObjectSignalHandler { + 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 *>(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 TrackGObject : public boost::intrusive_ptr { + typedef boost::intrusive_ptr Base_t; + + // Frees the instance of boost::function which was allocated + // by connectSignal. + template static void signalDestroy(gpointer data, GClosure *closure) throw () { + delete reinterpret_cast< boost::function *>(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(g_object_ref(Base_t::get())); } + void take(C *ptr) { *this = steal(ptr); } + + static TrackGObject steal(C *ptr) { return TrackGObject(ptr, TRANSFER_REF); } + + template guint connectSignal(const char *signal, + const boost::function &callback) { + return g_signal_connect_data(Base_t::get(), signal, + G_CALLBACK(&GObjectSignalHandler::handler), + new boost::function(callback), + &signalDestroy, + GConnectFlags(0)); + } + void disconnectSignal(guint handlerID) { + g_signal_handler_disconnect(static_cast(Base_t::get()), + handlerID); + } +}; + +template class StealGObject : public TrackGObject { + public: + StealGObject(C *ptr) : TrackGObject(ptr, TRANSFER_REF) {} + StealGObject() {} + StealGObject(const StealGObject &other) : TrackGObject(other) {} +}; + +template class TrackGLib : public boost::intrusive_ptr { + typedef boost::intrusive_ptr 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(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 StealGLib : public TrackGLib { + public: + StealGLib(C *ptr) : TrackGLib(ptr, TRANSFER_REF) {} + StealGLib() {} + StealGLib(const StealGLib &other) : TrackGLib(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("notify", + * boost::bind(...)); + * // Signature is taken from boost::function parameter. + * guint handlerID = + * object.connectSignal("notify", + * boost::function(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 : "<>"; } + + /** 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: + * : |failure + */ + void throwError(const std::string &action); + static void throwError(const std::string &action, const GError *err); +}; + +template void NoopDestructor(T *) {} +template void GObjectDestructor(T *ptr) { g_object_unref(ptr); } +template void GFreeDestructor(T *ptr) { g_free(static_cast(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, 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 { + 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 { + 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 > GStringListFreeCXX; +/** use this for a list which does not own the strings it points to */ +typedef GListCXX GStringListNoFreeCXX; + +/** + * Wraps a C gchar array and takes care of freeing the memory. + */ +class PlainGStr : public boost::shared_ptr +{ + public: + PlainGStr() {} + PlainGStr(gchar *str) : boost::shared_ptr(str, g_free) {} + PlainGStr(const PlainGStr &other) : boost::shared_ptr(other) {} + PlainGStr(const boost::shared_ptr &other) : boost::shared_ptr(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 *)this; } +}; + +/** + * Wraps a glib string array, frees with g_strfreev(). + */ +class PlainGStrArray : public boost::shared_ptr +{ + public: + PlainGStrArray() {} + PlainGStrArray(gchar **array) : boost::shared_ptr(array, g_strfreev) {} + PlainGStrArray(const PlainGStrArray &other) : boost::shared_ptr(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 index 0000000..26aa3c9 --- /dev/null +++ b/src/Contact/contacts2ebook/README @@ -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 +$ & +$ 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 index 0000000..cedb2d8 --- /dev/null +++ b/src/Contact/contacts2ebook/contacts.h @@ -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 +#include +#include + +#include + +#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 > UIDList; +typedef GListCXX >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 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 contacts_record_h; +static inline void contacts_record_destroy(contacts_record_h &handle, bool) { handle.reset(); } + +typedef GListCXX > 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 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 : public EContactStringType {}; +template<> struct EContactTraits : public EContactStringType {}; +template<> struct EContactTraits : public EContactStringType {}; +template<> struct EContactTraits : public EContactStringType {}; +template<> struct EContactTraits : public EContactStringType {}; +template<> struct EContactTraits : public EContactStringType {}; +template<> struct EContactTraits : public EContactStringType {}; +template<> struct EContactTraits : public EContactStringType {}; +template<> struct EContactTraits : public EContactStringType {}; +template<> struct EContactTraits : public EContactStringType {}; +template<> struct EContactTraits : public EContactStringType {}; +template<> struct EContactTraits : public EContactStringType {}; +template<> struct EContactTraits { + typedef EContactPhoto type; + static void free(EContactPhoto *ptr) { e_contact_photo_free(ptr); } +}; +template<> struct EContactTraits { + typedef EContactName type; + static void free(EContactName *ptr) { e_contact_name_free(ptr); } +}; +template<> struct EContactTraits : public EContactDateType {}; +template<> struct EContactTraits : public EContactDateType {}; +template struct EContactFieldCXX { + static boost::shared_ptr::type> get(EContact *contact) { + return boost::shared_ptr::type>(static_cast::type *>(e_contact_get(contact, field)), + free); + } + static void set(EContact *contact, const typename EContactTraits::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_ -- 2.7.4