/* * * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file * distributed with this work for additional information * regarding copyright ownership. The ASF licenses this file * to you 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. * */ #include "contacts.h" #if defined QTCONTACTS_USE_NAMESPACE QTCONTACTS_USE_NAMESPACE #endif Contacts::Contacts(Cordova *cordova): CPlugin(cordova) { m_fieldNamePairs.clear(); m_fieldNamePairs["displayName"] = QContactDetail::TypeDisplayLabel; m_fieldNamePairs["name"] = QContactDetail::TypeName; m_fieldNamePairs["nickname"] = QContactDetail::TypeNickname; m_fieldNamePairs["phoneNumbers"] = QContactDetail::TypePhoneNumber; m_fieldNamePairs["emails"] = QContactDetail::TypeEmailAddress; m_fieldNamePairs["addresses"] = QContactDetail::TypeAddress; m_fieldNamePairs["ims"] = QContactDetail::TypeOnlineAccount; m_fieldNamePairs["organizations"] = QContactDetail::TypeOrganization; m_fieldNamePairs["birthday"] = QContactDetail::TypeBirthday; m_fieldNamePairs["note"] = QContactDetail::TypeNote; m_fieldNamePairs["photos"] = QContactDetail::TypeAvatar; m_fieldNamePairs["urls"] = QContactDetail::TypeUrl; m_notSupportedFields.clear(); m_notSupportedFields << "categories"; m_manager.clear(); m_manager = QSharedPointer<QContactManager>(new QContactManager()); } void Contacts::save(int scId, int ecId, const QVariantMap ¶ms) { QContact result; QList<QContactDetail *> detailsToDelete; if (params.find("id") != params.end()) { QString id = params.find("id")->toString(); if (!id.isEmpty()) { result = m_manager->contact(QContactId::fromString(id)); result.clearDetails(); } } foreach (QString field, params.keys()) { QContactDetail::DetailType qtDefinition = cordovaFieldNameToQtDefinition(field); if (qtDefinition == QContactDetail::TypeUndefined) continue; if (field == "nickname") { QContactNickname *detail = new QContactNickname; detail->setNickname(params[field].toString()); detailsToDelete << detail; result.saveDetail(detail); } else if (field == "note") { QContactNote *detail = new QContactNote; detail->setNote(params[field].toString()); detailsToDelete << detail; result.saveDetail(detail); } else if (field == "phoneNumbers") { if (params[field].type() != QVariant::List) continue; QVariantList phonesList = params[field].toList(); foreach (const QVariant &phoneDesc, phonesList) { if (phoneDesc.type() != QVariant::Map) continue; QContactPhoneNumber *detail = new QContactPhoneNumber; detail->setNumber(phoneDesc.toMap()["value"].toString()); if (!phoneDesc.toMap()["type"].toString().isEmpty() && phoneDesc.toMap()["type"].toString() != "phone") detail->setSubTypes(QList<int>() << subTypePhoneFromString(phoneDesc.toMap()["type"].toString())); detailsToDelete << detail; result.saveDetail(detail); } } else if (field == "emails") { if (params[field].type() != QVariant::List) continue; QVariantList emailsList = params[field].toList(); foreach (const QVariant &emailDesc, emailsList) { if (emailDesc.type() != QVariant::Map) continue; if (emailDesc.toMap()["value"].toString().isEmpty()) continue; QContactEmailAddress *detail = new QContactEmailAddress; detail->setEmailAddress(emailDesc.toMap()["value"].toString()); detailsToDelete << detail; result.saveDetail(detail); } } else if (field == "ims") { if (params[field].type() != QVariant::List) continue; QVariantList imsList = params[field].toList(); foreach (const QVariant &imDesc, imsList) { if (imDesc.type() != QVariant::Map) continue; QContactOnlineAccount *detail = new QContactOnlineAccount; detail->setAccountUri(imDesc.toMap()["value"].toString()); if (!imDesc.toMap()["type"].toString().isEmpty()) detail->setSubTypes(QList<int>() << subTypeOnlineAccountFromString(imDesc.toMap()["type"].toString())); detailsToDelete << detail; result.saveDetail(detail); } } else if (field == "photos") { if (params[field].type() != QVariant::List) continue; QVariantList photosList = params[field].toList(); foreach (const QVariant &photoDesc, photosList) { if (photoDesc.type() != QVariant::Map) continue; //TODO: we need to decide should we support base64 images or not if (photoDesc.toMap()["type"].toString() != "url") continue; QContactAvatar *detail = new QContactAvatar; detail->setImageUrl(QUrl(photoDesc.toMap()["value"].toString())); detailsToDelete << detail; result.saveDetail(detail); } } else if (field == "urls") { if (params[field].type() != QVariant::List) continue; QVariantList urlsList = params[field].toList(); foreach (const QVariant &urlDesc, urlsList) { if (urlDesc.type() != QVariant::Map) continue; QContactUrl *detail = new QContactUrl; detail->setUrl(urlDesc.toMap()["value"].toString()); if (!urlDesc.toMap()["type"].toString().isEmpty()) detail->setSubType((QContactUrl::SubType) subTypeUrlFromString(urlDesc.toMap()["type"].toString())); detailsToDelete << detail; result.saveDetail(detail); } } else if (field == "birthday") { QDateTime birthday; birthday.setTime_t(params[field].toLongLong() / 1000); QContactBirthday *detail = new QContactBirthday; detail->setDateTime(birthday); detailsToDelete << detail; result.saveDetail(detail); } else if (field == "organizations") { if (params[field].type() != QVariant::List) continue; QVariantList organizationsList = params[field].toList(); foreach (const QVariant &organizationDesc, organizationsList) { if (organizationDesc.type() != QVariant::Map) continue; QContactOrganization *detail = new QContactOrganization; detail->setName(organizationDesc.toMap()["name"].toString()); detail->setDepartment(QStringList() << organizationDesc.toMap()["department"].toString()); detail->setRole(organizationDesc.toMap()["title"].toString()); detailsToDelete << detail; result.saveDetail(detail); } } else if (field == "name") { QContactName *detail = new QContactName; QVariantMap nameMap = params[field].toMap(); detail->setLastName(nameMap["familyName"].toString()); detail->setFirstName(nameMap["givenName"].toString()); detail->setMiddleName(nameMap["middleName"].toString()); detail->setPrefix(nameMap["honorificPrefix"].toString()); detail->setSuffix(nameMap["honorificSuffix"].toString()); detailsToDelete << detail; result.saveDetail(detail); } } if (!m_manager->saveContact(&result)) { switch (m_manager->error()) { case QContactManager::DoesNotExistError: case QContactManager::AlreadyExistsError: case QContactManager::InvalidDetailError: case QContactManager::InvalidRelationshipError: case QContactManager::BadArgumentError: case QContactManager::InvalidContactTypeError: callback(ecId, "ContactError.INVALID_ARGUMENT_ERROR"); break; case QContactManager::DetailAccessError: case QContactManager::PermissionsError: callback(ecId, "ContactError.PERMISSION_DENIED_ERROR"); break; case QContactManager::NotSupportedError: callback(ecId, "ContactError.NOT_SUPPORTED_ERROR"); break; case QContactManager::TimeoutError: callback(ecId, "ContactError.TIMEOUT_ERROR"); break; case QContactManager::UnspecifiedError: case QContactManager::LockedError: case QContactManager::OutOfMemoryError: case QContactManager::VersionMismatchError: case QContactManager::LimitReachedError: case QContactManager::NoError: default: callback(ecId, "ContactError.UNKNOWN_ERROR"); break; } } else { callback(scId, jsonedContact(result)); } qDeleteAll(detailsToDelete); } void Contacts::remove(int scId, int ecId, const QString &localId) { QContactId id = QContactId::fromString(localId); if (!m_manager->removeContact(id)) { switch (m_manager->error()) { case QContactManager::AlreadyExistsError: case QContactManager::InvalidDetailError: case QContactManager::InvalidRelationshipError: case QContactManager::BadArgumentError: case QContactManager::InvalidContactTypeError: callback(ecId, "ContactError.INVALID_ARGUMENT_ERROR"); break; case QContactManager::DetailAccessError: case QContactManager::PermissionsError: callback(ecId, "ContactError.PERMISSION_DENIED_ERROR"); break; case QContactManager::NotSupportedError: callback(ecId, "ContactError.NOT_SUPPORTED_ERROR"); break; case QContactManager::TimeoutError: callback(ecId, "ContactError.TIMEOUT_ERROR"); break; case QContactManager::UnspecifiedError: case QContactManager::LockedError: case QContactManager::OutOfMemoryError: case QContactManager::VersionMismatchError: case QContactManager::LimitReachedError: case QContactManager::NoError: case QContactManager::DoesNotExistError: default: callback(ecId, "ContactError.UNKNOWN_ERROR"); break; } } else { cb(scId); } } void Contacts::search(int scId, int ecId, const QStringList &fields, const QVariantMap ¶ms) { QString filter; bool multiple = true; if (params.find("filter") != params.end()) { filter = params["filter"].toString(); } if (params.find("multiple") != params.end()) { multiple = params["multiple"].toBool(); } findContacts(scId, ecId, fields, filter, multiple); } void Contacts::findContacts(int scId, int ecId, const QStringList &fields, const QString &filter, bool multiple) { if (fields.length() <= 0){ callback(ecId, "new ContactError(ContactError.INVALID_ARGUMENT_ERROR)"); } QContactUnionFilter unionFilter; QMap<QContactDetail::DetailType, QList<int> > fieldNames; fieldNames[QContactDetail::TypeDisplayLabel] << QContactDisplayLabel::FieldLabel; fieldNames[QContactDetail::TypeName] << QContactName::FieldFirstName << QContactName::FieldLastName << QContactName::FieldMiddleName << QContactName::FieldPrefix << QContactName::FieldSuffix; fieldNames[QContactDetail::TypeNickname] << QContactNickname::FieldNickname; fieldNames[QContactDetail::TypePhoneNumber] << QContactPhoneNumber::FieldNumber; fieldNames[QContactDetail::TypeEmailAddress] << QContactEmailAddress::FieldEmailAddress; fieldNames[QContactDetail::TypeAddress] << QContactAddress::FieldCountry << QContactAddress::FieldLocality << QContactAddress::FieldPostcode << QContactAddress::FieldPostOfficeBox << QContactAddress::FieldRegion << QContactAddress::FieldStreet; fieldNames[QContactDetail::TypeOnlineAccount] << QContactOnlineAccount::FieldAccountUri; fieldNames[QContactDetail::TypeOrganization] << QContactOrganization::FieldAssistantName << QContactOrganization::FieldDepartment << QContactOrganization::FieldLocation << QContactOrganization::FieldName << QContactOrganization::FieldRole << QContactOrganization::FieldTitle; fieldNames[QContactDetail::TypeBirthday] << QContactBirthday::FieldBirthday; fieldNames[QContactDetail::TypeNote] << QContactNote::FieldNote; fieldNames[QContactDetail::TypeUrl] << QContactUrl::FieldUrl; foreach (const QContactDetail::DetailType &defName, fieldNames.keys()) { foreach(int fieldName, fieldNames[defName]) { QContactDetailFilter subFilter; subFilter.setDetailType(defName, fieldName); subFilter.setValue(filter); subFilter.setMatchFlags(QContactFilter::MatchContains); unionFilter.append(subFilter); } } QList<QContact> contacts = m_manager->contacts(unionFilter); if (contacts.empty()) { callback(scId, "[]"); } else { QStringList stringifiedContacts; foreach (const QContact &contact, contacts) { stringifiedContacts << jsonedContact(contact, fields); if (!multiple) break; } callback(scId, QString("[%1]").arg(stringifiedContacts.join(", "))); } } QContactDetail::DetailType Contacts::cordovaFieldNameToQtDefinition(const QString &cordovaFieldName) const { if (m_fieldNamePairs.contains(cordovaFieldName)) return m_fieldNamePairs[cordovaFieldName]; return QContactDetail::TypeUndefined; } int Contacts::subTypePhoneFromString(const QString &cordovaSubType) const { QString preparedSubType = cordovaSubType.toLower(); if (preparedSubType == "mobile") return QContactPhoneNumber::SubTypeMobile; else if (preparedSubType == "fax") return QContactPhoneNumber::SubTypeFax; else if (preparedSubType == "pager") return QContactPhoneNumber::SubTypePager; else if (preparedSubType == "voice") return QContactPhoneNumber::SubTypeVoice; else if (preparedSubType == "modem") return QContactPhoneNumber::SubTypeModem; else if (preparedSubType == "video") return QContactPhoneNumber::SubTypeVideo; else if (preparedSubType == "car") return QContactPhoneNumber::SubTypeCar; else if (preparedSubType == "assistant") return QContactPhoneNumber::SubTypeAssistant; return QContactPhoneNumber::SubTypeLandline; } int Contacts::subTypeOnlineAccountFromString(const QString &cordovaSubType) const { QString preparedSubType = cordovaSubType.toLower(); if (preparedSubType == "aim") return QContactOnlineAccount::ProtocolAim; else if (preparedSubType == "icq") return QContactOnlineAccount::ProtocolIcq; else if (preparedSubType == "irc") return QContactOnlineAccount::ProtocolIrc; else if (preparedSubType == "jabber") return QContactOnlineAccount::ProtocolJabber; else if (preparedSubType == "msn") return QContactOnlineAccount::ProtocolMsn; else if (preparedSubType == "qq") return QContactOnlineAccount::ProtocolQq; else if (preparedSubType == "skype") return QContactOnlineAccount::ProtocolSkype; else if (preparedSubType == "yahoo") return QContactOnlineAccount::ProtocolYahoo; return QContactOnlineAccount::ProtocolUnknown; } int Contacts::subTypeUrlFromString(const QString &cordovaSubType) const { QString preparedSubType = cordovaSubType.toLower(); if (preparedSubType == "blog") return QContactUrl::SubTypeBlog; else if (preparedSubType == "favourite") return QContactUrl::SubTypeFavourite; return QContactUrl::SubTypeHomePage; } QString Contacts::subTypePhoneToString(int qtSubType) const { if (qtSubType == QContactPhoneNumber::SubTypeMobile) return "mobile"; else if (qtSubType == QContactPhoneNumber::SubTypeFax) return "fax"; else if (qtSubType == QContactPhoneNumber::SubTypePager) return "pager"; else if (qtSubType == QContactPhoneNumber::SubTypeVoice) return "voice"; else if (qtSubType == QContactPhoneNumber::SubTypeModem) return "modem"; else if (qtSubType == QContactPhoneNumber::SubTypeVideo) return "video"; else if (qtSubType == QContactPhoneNumber::SubTypeCar) return "car"; else if (qtSubType == QContactPhoneNumber::SubTypeAssistant) return "assistant"; return "home"; } QString Contacts::subTypeOnlineAccountToString(int qtSubType) const { if (qtSubType == QContactOnlineAccount::ProtocolAim) return "aim"; else if (qtSubType == QContactOnlineAccount::ProtocolIcq) return "icq"; else if (qtSubType == QContactOnlineAccount::ProtocolIrc) return "irc"; else if (qtSubType == QContactOnlineAccount::ProtocolJabber) return "jabber"; else if (qtSubType == QContactOnlineAccount::ProtocolMsn) return "msn"; else if (qtSubType == QContactOnlineAccount::ProtocolQq) return "qq"; else if (qtSubType == QContactOnlineAccount::ProtocolSkype) return "skype"; else if (qtSubType == QContactOnlineAccount::ProtocolYahoo) return "yahoo"; return "unknown"; } QString Contacts::subTypeUrlToString(int qtSubType) const { if (qtSubType == QContactUrl::SubTypeBlog) return "blog"; else if (qtSubType == QContactUrl::SubTypeFavourite) return "favourite"; return "homepage"; } QString Contacts::jsonedContact(const QContact &contact, const QStringList &fields) const { QStringList resultingFields = fields; if (resultingFields.empty()) resultingFields.append(m_fieldNamePairs.keys()); if (!resultingFields.contains("id")) resultingFields << "id"; QStringList fieldValuesList; foreach (const QString &field, resultingFields) { QContactDetail::DetailType qtDefinitionName = cordovaFieldNameToQtDefinition(field); if (field == "id") { fieldValuesList << QString("%1: \"%2\"") .arg(field) .arg(contact.id().toString()); } else if (field == "displayName") { QContactDisplayLabel detail = contact.detail(qtDefinitionName); fieldValuesList << QString("%1: \"%2\"") .arg(field) .arg(detail.label()); } else if (field == "nickname") { QContactNickname detail = contact.detail(qtDefinitionName); fieldValuesList << QString("%1: \"%2\"") .arg(field) .arg(detail.nickname()); } else if (field == "note") { QContactNote detail = contact.detail(qtDefinitionName); fieldValuesList << QString("%1: \"%2\"") .arg(field) .arg(detail.note()); } else if (field == "phoneNumbers") { QStringList fieldValues; QList<QContactDetail> details = contact.details(qtDefinitionName); foreach (const QContactDetail &detail, details) { QContactPhoneNumber castedDetail = detail; QStringList subTypes; foreach (int subType, castedDetail.subTypes()) subTypes << subTypePhoneToString(subType); if (subTypes.isEmpty()) subTypes << "phone"; foreach(const QString &subType, subTypes) { fieldValues << QString("{type: \"%1\", value: \"%2\", pref: %3}") .arg(subType) .arg(castedDetail.number()) .arg("false"); } } fieldValuesList << QString("%1: [%2]") .arg(field) .arg(fieldValues.join(", ")); } else if (field == "emails") { QStringList fieldValues; QList<QContactDetail> details = contact.details(qtDefinitionName); foreach (const QContactDetail &detail, details) { QContactEmailAddress castedDetail = detail; fieldValues << QString("{type: \"%1\", value: \"%2\", pref: %3}") .arg("email") .arg(castedDetail.emailAddress()) .arg("false"); } fieldValuesList << QString("%1: [%2]") .arg(field) .arg(fieldValues.join(", ")); } else if (field == "ims") { QStringList fieldValues; QList<QContactDetail> details = contact.details(qtDefinitionName); foreach (const QContactDetail &detail, details) { QContactOnlineAccount castedDetail = detail; QStringList subTypes; foreach (int subType, castedDetail.subTypes()) subTypes << subTypeOnlineAccountToString(subType); if (subTypes.isEmpty()) subTypes << "IM"; foreach(const QString &subType, subTypes) { fieldValues << QString("{type: \"%1\", value: \"%2\", pref: %3}") .arg(subType) .arg(castedDetail.accountUri()) .arg("false"); } } fieldValuesList << QString("%1: [%2]") .arg(field) .arg(fieldValues.join(", ")); } else if (field == "photos") { QStringList fieldValues; QList<QContactDetail> details = contact.details(qtDefinitionName); foreach (const QContactDetail &detail, details) { QContactAvatar castedDetail = detail; fieldValues << QString("{type: \"%1\", value: \"%2\", pref: %3}") .arg("url") .arg(castedDetail.imageUrl().toString()) .arg("false"); } fieldValuesList << QString("%1: [%2]") .arg(field) .arg(fieldValues.join(", ")); } else if (field == "urls") { QStringList fieldValues; QList<QContactDetail> details = contact.details(qtDefinitionName); foreach (const QContactDetail &detail, details) { QContactUrl castedDetail = detail; QString subType = subTypeUrlToString(castedDetail.subType()); fieldValues << QString("{type: \"%1\", value: \"%2\", pref: %3}") .arg(subType) .arg(castedDetail.url()) .arg("false"); } fieldValuesList << QString("%1: [%2]") .arg(field) .arg(fieldValues.join(", ")); } else if (field == "birthday") { QContactBirthday detail = contact.detail(qtDefinitionName); fieldValuesList << QString("%1: %2") .arg(field) .arg(detail.dateTime().toMSecsSinceEpoch()); } else if (field == "organizations") { QStringList fieldValues; QList<QContactDetail> details = contact.details(qtDefinitionName); foreach (const QContactDetail &detail, details) { QContactOrganization castedDetail = detail; fieldValues << QString("{type: \"%1\", name: \"%2\", department: \"%3\", title: \"%4\", pref: %5}") .arg("organization") .arg(castedDetail.name()) .arg(castedDetail.department().join(" ")) .arg(castedDetail.role()) .arg("false"); } fieldValuesList << QString("%1: [%2]") .arg(field) .arg(fieldValues.join(", ")); } else if (field == "name") { QContactName detail = contact.detail(qtDefinitionName); fieldValuesList << QString("%1: {familyName: \"%2\", givenName: \"%3\", middleName: \"%4\", honorificPrefix: \"%5\", honorificSuffix: \"%6\"}") .arg(field) .arg(detail.lastName()) .arg(detail.firstName()) .arg(detail.middleName()) .arg(detail.prefix()) .arg(detail.suffix()); } } return QString("{%1}").arg(fieldValuesList.join(", ")); }