diff -r 90517678cc4f -r 453da2cfceef qtmobility/plugins/contacts/maemo5/qcontactabook.cpp --- a/qtmobility/plugins/contacts/maemo5/qcontactabook.cpp Mon May 03 13:18:40 2010 +0300 +++ b/qtmobility/plugins/contacts/maemo5/qcontactabook.cpp Fri May 14 16:41:33 2010 +0300 @@ -73,6 +73,7 @@ QContactABook* that; bool *result; char *uid; + QContactManager::Error *error; }; /* QContactABook */ @@ -109,7 +110,7 @@ cbSharedData* d = static_cast(data); if (!d){ - qWarning() << "d has been deleted"; + //qWarning() << "d has been deleted"; return; } @@ -127,7 +128,9 @@ if (id) contactIds << id; } - d->that->_contactsAdded(contactIds); + + if (!contactIds.isEmpty()) + d->that->_contactsAdded(contactIds); } static void contactsChangedCB(OssoABookRoster *roster, OssoABookContact **contacts, gpointer data) @@ -137,7 +140,7 @@ cbSharedData* d = static_cast(data); if (!d){ - qWarning() << "d has been deleted"; + //qWarning() << "d has been deleted"; return; } @@ -154,7 +157,9 @@ if (id) contactIds << id; } - d->that->_contactsChanged(contactIds); + + if (!contactIds.isEmpty()) + d->that->_contactsChanged(contactIds); } static void contactsRemovedCB(OssoABookRoster *roster, const char **ids, gpointer data) @@ -164,7 +169,7 @@ cbSharedData* d = static_cast(data); if (!d){ - qWarning() << "d has been deleted"; + //qWarning() << "d has been deleted"; return; } @@ -172,13 +177,15 @@ QList contactIds; for (p = ids; *p; ++p) { - QContactLocalId id = d->hash->take(*p); - QCM5_DEBUG << "Contact" << id << "has been removed"; - if (id) - contactIds << id; + QContactLocalId id = d->hash->take(*p); + if (id) { + QCM5_DEBUG << "Contact" << id << "has been removed"; + contactIds << id; + } } - d->that->_contactsRemoved(contactIds); + if (!contactIds.isEmpty()) + d->that->_contactsRemoved(contactIds); } void QContactABook::initAddressBook(){ @@ -239,7 +246,7 @@ contactList = osso_abook_aggregator_list_master_contacts(m_abookAgregator); if (!contactList) { - qWarning() << "There are no Master contacts. LocalId hash is empty."; + //qWarning() << "There are no Master contacts. LocalId hash is empty."; return; } @@ -261,8 +268,30 @@ QList QContactABook::contactIds(const QContactFilter& filter, const QList& sortOrders, QContactManager::Error* error) const { QList rtn; - - /* Sorting */ + + // do this naively for now... + *error = QContactManager::NoError; + QContactManager::Error tempError = QContactManager::NoError; + QList allIds = m_localIds.keys(); + QList sortedAndFiltered; + QContact *curr = 0; + foreach (const QContactLocalId& currId, allIds) { + curr = getQContact(currId, &tempError); + if (tempError != QContactManager::NoError) + *error = tempError; + if (QContactManagerEngine::testFilter(filter, *curr)) { + QContactManagerEngine::addSorted(&sortedAndFiltered, *curr, sortOrders); + } + delete curr; + } + + foreach (const QContact& contact, sortedAndFiltered) { + rtn.append(contact.localId()); + } + return rtn; + + /* + // Sorting //NOTE Native sorting is possible thanks to g_list_sort. // It's limited just to one filter. // Multi filters support need non native sorting. @@ -296,40 +325,6 @@ return QContactManagerEngine::sortContacts(contacts, sortOrders); } - /* Matching action filter */ - //NOTE The code was not really tested */ - if(filter.type() == QContactFilter::ActionFilter){ - QContactActionFilter af(filter); - /* This looks a bit strange for me */ - QList descriptors = QContactAction::actionDescriptors(af.actionName(), af.vendorName(), af.implementationVersion()); - - GList *masterContacts = osso_abook_aggregator_list_master_contacts(m_abookAgregator); - for(; masterContacts; ){ - OssoABookContact *masterContact = A_CONTACT(masterContacts->data); - bool match = contactActionsMatch(masterContact, descriptors); - if(!match) { - GList *rosterContacts = osso_abook_contact_get_roster_contacts(masterContact); - for(; rosterContacts && !match; ){ - OssoABookContact *rosterContact = A_CONTACT(rosterContacts->data); - match = contactActionsMatch(rosterContact, descriptors); - rosterContacts = g_list_delete_link(rosterContacts, rosterContacts); - } - g_list_free(rosterContacts); - } - if(match){ - EContact *contact = E_CONTACT(masterContact); - const char* data = CONST_CHAR(e_contact_get_const(contact, E_CONTACT_UID)); - QByteArray localId(data); - m_localIds << localId; - rtn.append(m_localIds[localId]); - QCM5_DEBUG << "eContactID " << localId << "has been stored in m_localIDs with key" << m_localIds[localId]; - } - masterContacts = g_list_delete_link(masterContacts, masterContacts); - } - *error = QContactManager::NoError; - return rtn; - } - EBookQuery* query = convert(filter); GList* l = osso_abook_aggregator_find_contacts(m_abookAgregator, query); @@ -348,23 +343,66 @@ *error = QContactManager::NoError; return rtn; + */ } QContact* QContactABook::getQContact(const QContactLocalId& contactId, QContactManager::Error* error) const { QContact *rtn; - OssoABookContact* aContact = getAContact(contactId); + OssoABookContact* aContact = getAContact(contactId, error); if (!aContact) { - qWarning() << "Unable to get a valid AContact"; - *error = QContactManager::DoesNotExistError; + //qWarning() << "Unable to get a valid AContact"; return new QContact; } //Convert aContact => qContact rtn = convert(E_CONTACT(aContact)); + QContactId cId; + cId.setLocalId(contactId); + rtn->setId(cId); return rtn; } +static QContactManager::Error getErrorFromStatus(const EBookStatus status){ + switch (status) { + case E_BOOK_ERROR_OK: + return QContactManager::NoError; + case E_BOOK_ERROR_INVALID_ARG: + return QContactManager::BadArgumentError; + case E_BOOK_ERROR_BUSY: + return QContactManager::LockedError; + case E_BOOK_ERROR_PERMISSION_DENIED: + case E_BOOK_ERROR_AUTHENTICATION_FAILED: + case E_BOOK_ERROR_AUTHENTICATION_REQUIRED: + //case E_BOOK_ERROR_UNSUPPORTED_AUTHENTICATION_METHOD: //Missing in current Maemo5 Ebook lib version + return QContactManager::PermissionsError; + case E_BOOK_ERROR_CONTACT_NOT_FOUND: + return QContactManager::DoesNotExistError; + case E_BOOK_ERROR_CONTACT_ID_ALREADY_EXISTS: + return QContactManager::AlreadyExistsError; + case E_BOOK_ERROR_NO_SPACE: + return QContactManager::OutOfMemoryError; +#if 0 + case E_BOOK_ERROR_REPOSITORY_OFFLINE: + case E_BOOK_ERROR_NO_SUCH_BOOK: + case E_BOOK_ERROR_NO_SELF_CONTACT: + case E_BOOK_ERROR_SOURCE_NOT_LOADED: + case E_BOOK_ERROR_SOURCE_ALREADY_LOADED: + case E_BOOK_ERROR_PROTOCOL_NOT_SUPPORTED: + case E_BOOK_ERROR_CANCELLED: + case E_BOOK_ERROR_COULD_NOT_CANCEL: + case E_BOOK_ERROR_TLS_NOT_AVAILABLE: + case E_BOOK_ERROR_CORBA_EXCEPTION: + case E_BOOK_ERROR_NO_SUCH_SOURCE: + case E_BOOK_ERROR_OFFLINE_UNAVAILABLE: + case E_BOOK_ERROR_OTHER_ERROR: + case E_BOOK_ERROR_INVALID_SERVER_VERSION: +#endif + default: + return QContactManager::UnspecifiedError; + } +} + static void delContactCB(EBook *book, EBookStatus status, gpointer closure) { Q_UNUSED(book); @@ -375,11 +413,12 @@ return; *sd->result = (status != E_BOOK_ERROR_OK && - status != E_BOOK_ERROR_CONTACT_NOT_FOUND) ? false : true; + status != E_BOOK_ERROR_CONTACT_NOT_FOUND) ? false : true; + *sd->error = getErrorFromStatus(status); + sd->that->_jobRemovingCompleted(); } -//### FIXME error is not managed bool QContactABook::removeContact(const QContactLocalId& contactId, QContactManager::Error* error) { Q_UNUSED(error); @@ -389,9 +428,9 @@ OssoABookRoster *roster = A_ROSTER(m_abookAgregator); EBook *book = osso_abook_roster_get_book(roster); - OssoABookContact *aContact = getAContact(contactId); + OssoABookContact *aContact = getAContact(contactId, error); if (!OSSO_ABOOK_IS_CONTACT(aContact)){ - qWarning() << "aCtontact is not a valid ABook contact"; + //qWarning() << "Specified contact is not a valid ABook contact"; return false; } @@ -407,6 +446,7 @@ m_deleteJobSD = new jobSharedData; m_deleteJobSD->that = this; m_deleteJobSD->result = &ok; + m_deleteJobSD->error = error; //Remove photos EContactPhoto *photo = NULL; @@ -425,6 +465,7 @@ GList* rosterContacts = NULL; rosterContacts = osso_abook_contact_get_roster_contacts(aContact); const char *masterUid = CONST_CHAR(e_contact_get_const(E_CONTACT(aContact), E_CONTACT_UID)); + char *contactUidCopy = strdup(masterUid); while(rosterContacts){ OssoABookContact *rosterContact = A_CONTACT(rosterContacts->data); osso_abook_contact_reject_for_uid(rosterContact, masterUid, NULL); @@ -436,6 +477,15 @@ delContactCB, m_deleteJobSD); loop.exec(QEventLoop::AllEvents|QEventLoop::WaitForMoreEvents); + + // update our list of ids... + QContactLocalId id = m_localIds[contactUidCopy]; + m_localIds.remove(contactUidCopy); + if (contactUidCopy) + free(contactUidCopy); + + if (id) + _contactsRemoved(QList() << id); return ok; } @@ -444,18 +494,25 @@ { Q_UNUSED(book) jobSharedData *sd = static_cast(user_data); + if (!sd) + return; - *sd->result = (status == E_BOOK_ERROR_OK) ? true : false; + *sd->result = (status == E_BOOK_ERROR_OK) ? true : false; + *sd->error = getErrorFromStatus(status); sd->that->_jobSavingCompleted(); } static void addContactCB(EBook* book, EBookStatus status, const char *uid, gpointer user_data) { jobSharedData *sd = static_cast(user_data); + if (!sd) + return; + if (uid) sd->uid = strdup(uid); - - //osso_abook_contact_set_roster(OssoABookContact *contact, OssoABookRoster *roster) + + //### FIXME IS THIS LINE REALLY NEEDED: osso_abook_contact_set_roster(OssoABookContact *contact, OssoABookRoster *roster) + *sd->result = (status == E_BOOK_ERROR_OK) ? true : false; commitContactCB(book, status, user_data); } @@ -478,10 +535,9 @@ book = osso_abook_roster_get_book(roster); } - // Conver QContact to AContact - aContact = convert(contact); + // Convert QContact to AContact + aContact = convert(contact, error); if (!aContact){ - *error = QContactManager::UnspecifiedError; return false; } @@ -497,10 +553,13 @@ m_saveJobSD = new jobSharedData; m_saveJobSD->that = this; m_saveJobSD->result = &ok; + m_saveJobSD->error = error; + m_saveJobSD->uid = 0; // Add/Commit the contact uid = CONST_CHAR(e_contact_get_const(E_CONTACT (aContact), E_CONTACT_UID)); if (uid) { + m_saveJobSD->uid = strdup(uid); osso_abook_contact_async_commit(aContact, book, commitContactCB, m_saveJobSD); } else { osso_abook_contact_async_add(aContact, book, addContactCB, m_saveJobSD); @@ -508,11 +567,15 @@ loop.exec(QEventLoop::AllEvents|QEventLoop::WaitForMoreEvents); + // save the newly saved contact's id in the hash. + m_localIds << m_saveJobSD->uid; + // set the id of the contact. QContactId cId; cId.setLocalId(m_localIds[m_saveJobSD->uid]); contact->setId(cId); - //free(m_saveJobSD->uid); + if (m_saveJobSD->uid) + free(m_saveJobSD->uid); return ok; } @@ -534,7 +597,7 @@ QCM5_DEBUG << "eContactID " << eContactUID << "has been stored in m_localIDs with key" << id; } } else { - qWarning() << "Cannot find self contact"; + //qWarning() << "Cannot find self contact"; *errors = QContactManager::DoesNotExistError; id = 0; } @@ -542,38 +605,6 @@ return id; } -bool QContactABook::contactActionsMatch(OssoABookContact *contact, QList descriptors) const -{ - OssoABookCapsFlags capsFlags = osso_abook_caps_get_capabilities(OSSO_ABOOK_CAPS(contact)); - - if(capsFlags & OSSO_ABOOK_CAPS_NONE) - return false; - - /* ActionNames could be incorrect */ - OssoABookCapsFlags actionFlags = OSSO_ABOOK_CAPS_NONE; - for(int i = 0; i < descriptors.size(); i++){ - QString actionName = descriptors.at(i).actionName(); - QCM5_DEBUG << actionName; - if(!actionName.compare("Phone")) - actionFlags = (OssoABookCapsFlags)(actionFlags | OSSO_ABOOK_CAPS_PHONE); - else if(!actionName.compare("Voice")) - actionFlags = (OssoABookCapsFlags)(actionFlags | OSSO_ABOOK_CAPS_VOICE); - else if(!actionName.compare("SendEmail")) - actionFlags = (OssoABookCapsFlags)(actionFlags | OSSO_ABOOK_CAPS_EMAIL); - else if(!actionName.compare("Chat")) - actionFlags = (OssoABookCapsFlags)(actionFlags | OSSO_ABOOK_CAPS_CHAT); - else if(!actionName.compare("ChatAdditional")) - actionFlags = (OssoABookCapsFlags)(actionFlags | OSSO_ABOOK_CAPS_CHAT_ADDITIONAL); - else if(!actionName.compare("VoiceAdditional")) - actionFlags = (OssoABookCapsFlags)(actionFlags | OSSO_ABOOK_CAPS_VOICE_ADDITIONAL); - else if(!actionName.compare("Video")) - actionFlags = (OssoABookCapsFlags)(actionFlags | OSSO_ABOOK_CAPS_VIDEO); - else if(!actionName.compare("Addressbook")) - actionFlags = (OssoABookCapsFlags)(actionFlags | OSSO_ABOOK_CAPS_ADDRESSBOOK); - } - return ((actionFlags & capsFlags) == actionFlags); -} - EBookQuery* QContactABook::convert(const QContactFilter& filter) const { EBookQuery* query = NULL; @@ -626,7 +657,7 @@ case QContactFilter::MatchEndsWith: queryStr = "endswith"; break; default: queryStr = "contains"; - qWarning() << "Match flag not supported"; + //qWarning() << "Match flag not supported"; } static QHash hash; if (hash.isEmpty()){ @@ -644,14 +675,13 @@ QString eDetail = hash[f.detailDefinitionName()]; if (eDetail.isEmpty()){ - qWarning() << "Unable to found an ebook detail for " << f.detailDefinitionName(); + //qWarning() << "Unable to found an ebook detail for " << f.detailDefinitionName(); return NULL; } queryStr = queryStr + " \"" + eDetail + "\" \"" + f.value().toString() + "\""; query = e_book_query_from_string(qPrintable(queryStr)); } break; case QContactFilter::ActionFilter: - QCM5_DEBUG << "ActionFilter"; //eQuery doesn't support ActionFilter break; case QContactFilter::IntersectionFilter: { @@ -662,7 +692,7 @@ foreach(i, fs){ EBookQuery* q = convert(i); if (!q){ - qWarning() << "Query is null"; + //qWarning() << "Query is null"; continue; } if (query) @@ -680,7 +710,7 @@ foreach(i, fs){ EBookQuery* q = convert(i); if (!q){ - qWarning() << "Query is null"; + //qWarning() << "Query is null"; continue; } if (query) @@ -696,6 +726,7 @@ } break; default: QCM5_DEBUG << "Filter not supported"; + query = convert(QContactInvalidFilter()); } //Debugging @@ -778,7 +809,7 @@ ok = contact->saveDetail(detail); if (!ok){ - qWarning() << "Detail can't be saved into QContact"; + //qWarning() << "Detail can't be saved to QContact"; delete detail; continue; } @@ -812,13 +843,14 @@ return true; } -OssoABookContact* QContactABook::getAContact(const QContactLocalId& contactId) const +OssoABookContact* QContactABook::getAContact(const QContactLocalId& contactId, QContactManager::Error* error) const { OssoABookContact* rtn = NULL; QCM5_DEBUG << "Getting aContact with id " << m_localIds[contactId] << "local contactId is" << contactId; if(QString(m_localIds[contactId]).compare("osso-abook-self") == 0) { + *error = QContactManager::NoError; rtn = A_CONTACT(osso_abook_self_contact_get_default()); } else { EBookQuery* query; @@ -830,9 +862,13 @@ e_book_query_unref(query); if (g_list_length(contacts) == 1) { + *error = QContactManager::NoError; rtn = A_CONTACT(contacts->data); + } else if (g_list_length(contacts) == 0) { + *error = QContactManager::DoesNotExistError; } else { - qWarning("List is empty or several contacts have the same UID or contactId belongs to a roster contact."); + //qWarning("Several contacts have the same UID or contactId belongs to a roster contact."); + *error = QContactManager::UnspecifiedError; } if (contacts) g_list_free(contacts); @@ -850,7 +886,7 @@ const QByteArray eContactUID(data); QContactLocalId localId = m_localIds[eContactUID]; if (!localId) - qWarning("Unable to get valid localId for the specified eContaact UID"); + //qWarning("Unable to get valid localId for the specified eContaact UID"); rtn.setLocalId(localId); } return rtn; @@ -863,7 +899,7 @@ //Ordered list of Fields QStringList addressFields; addressFields << QContactAddress::FieldPostOfficeBox - << "Estension" //FIXME I'm not sure we have to use a new field + << AddressFieldExtension //XXX FIXME I'm not sure we have to use a new field << QContactAddress::FieldStreet << QContactAddress::FieldLocality << QContactAddress::FieldRegion @@ -933,7 +969,6 @@ map[QContactName::FieldCustomLabel] = eContactName->additional; map[QContactName::FieldFirstName] = eContactName->given; map[QContactName::FieldLastName] = eContactName->family; - //map[QContactName::FieldMiddleName] = eContactName-> map[QContactName::FieldPrefix] = eContactName->prefixes; map[QContactName::FieldSuffix] = eContactName->suffixes; e_contact_name_free (eContactName); @@ -1194,7 +1229,7 @@ attrIsOssoValid = paramName.contains("X-OSSO-VALID"); if (!attrIsType && !attrIsOssoValid) { - qWarning () << "Skipping attribute parameter checking for" << paramName; + //qWarning () << "Skipping attribute parameter checking for" << paramName; continue; } @@ -1205,7 +1240,7 @@ if (attrIsOssoValid) { ossoValidIsOk = (attributeParameterValue == "yes")? true : false; if (!ossoValidIsOk) { - qWarning() << "X-OSSO-VALID is false."; + //qWarning() << "X-OSSO-VALID is false."; break; } } else if (type.isEmpty()) { @@ -1233,7 +1268,7 @@ { QContactOrganization* rtn = new QContactOrganization; QVariantMap map; - const char* title = CONST_CHAR(e_contact_get(eContact, E_CONTACT_TITLE)); + const char* title = CONST_CHAR(e_contact_get(eContact, E_CONTACT_ORG)); map[QContactOrganization::FieldTitle] = title; FREE(title); setDetailValues(map, rtn); @@ -1379,7 +1414,7 @@ attrIsOssoValid = paramName.contains("X-OSSO-VALID"); if (!attrIsType && !attrIsOssoValid) { - qWarning () << "Skipping attribute parameter checking for" << paramName; + //qWarning () << "Skipping attribute parameter checking for" << paramName; continue; } @@ -1390,7 +1425,7 @@ if (attrIsOssoValid) { ossoValidIsOk = (attributeParameterValue == "yes")? true : false; if (!ossoValidIsOk) { - qWarning() << "X-OSSO-VALID is false."; + //qWarning() << "X-OSSO-VALID is false."; break; } } else if (type.isEmpty()) { @@ -1491,7 +1526,7 @@ int pos = g_list_position(attributeList, node); if (index > pos){ - qWarning() << "Attribute doesn't found at position" << index; + //qWarning() << "Attribute doesn't found at position" << index; return; } @@ -1568,26 +1603,17 @@ } } -OssoABookContact* QContactABook::convert(const QContact *contact) const +OssoABookContact* QContactABook::convert(const QContact *contact, QContactManager::Error* error) const { Q_CHECK_PTR(contact); - + OssoABookContact* rtn; // Get aContact if it exists or create a new one if it doesn't QContactLocalId id = contact->localId(); QCM5_DEBUG << "Converting QContact id:" << id << " to aContact"; - if (id){ - rtn = getAContact(id); - // It's not safe to commit changes to a contact that has been modified. - // This problem affects attributes with the same name and parameters such as - // EMail, Address... - QContactTimestamp* ts = getTimestampDetail(E_CONTACT(rtn)); - if (*ts != contact->detail()){ - delete ts; - return NULL; - } - delete ts; + if (id) { + rtn = getAContact(id, error); } else { rtn = osso_abook_contact_new(); } @@ -1671,7 +1697,7 @@ QString key = i.key(); if (key == QContactAddress::FieldPostOfficeBox) index = 0; - else if (key == "Estension") index = 1; + else if (key == AddressFieldExtension) index = 1; else if (key == QContactAddress::FieldStreet) index = 2; else if (key == QContactAddress::FieldLocality) index = 3; else if (key == QContactAddress::FieldRegion) index = 4; @@ -1680,7 +1706,7 @@ else if (key == QContactDetail::FieldContext) continue; else if (key == QContactDetail::FieldDetailUri) detailUri = i.value().toInt(); else { - qWarning() << "Address contains an invalid field:" << key; + //qWarning() << "Address contains an invalid field:" << key; return; } @@ -1823,16 +1849,16 @@ // Save First and Last name in the N vcard attribute { QStringList supportedDetailValues; - supportedDetailValues << QContactName::FieldFirstName << QContactName::FieldLastName; + supportedDetailValues << QContactName::FieldLastName << QContactName::FieldFirstName; foreach(QString key, supportedDetailValues){ attrValues << detail.value(key); } //REMOVE ME - We don't want to support custom label - if (attrValues[0].isEmpty()){ - qWarning() << "QContactName::FieldFirstName is empty"; - attrValues[0] = detail.customLabel(); + if (attrValues[1].isEmpty()){ + //qWarning() << "QContactName::FieldFirstName is empty"; + attrValues[1] = detail.customLabel(); } addAttributeToAContact(aContact, EVC_N, attrValues); @@ -1907,6 +1933,8 @@ QString value = i.value().toString(); if (value == QContactPhoneNumber::SubTypeMobile) value = "CELL"; + else if (value == QContactPhoneNumber::SubTypeVoice) + value = "VOICE"; paramValues << value.toUpper(); } else attrValues << i.value().toString(); @@ -1916,7 +1944,7 @@ if (paramValues.isEmpty()) paramValues << "VOICE"; - addAttributeToAContact(aContact, EVC_TEL, attrValues, EVC_TYPE, paramValues, true, detail.detailUri().toInt()); + addAttributeToAContact(aContact, EVC_TEL, attrValues, EVC_TYPE, paramValues, false, detail.detailUri().toInt()); } void QContactABook::setUrlDetail(const OssoABookContact* aContact, const QContactUrl& detail) const