diff --git a/js/ui/cordova/plugins/cordova-plugin-contacts/src/ubuntu/contacts.cpp b/js/ui/cordova/plugins/cordova-plugin-contacts/src/ubuntu/contacts.cpp new file mode 100644 index 0000000..373a276 --- /dev/null +++ b/js/ui/cordova/plugins/cordova-plugin-contacts/src/ubuntu/contacts.cpp @@ -0,0 +1,576 @@ +/* + * + * 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(new QContactManager()); +} + +void Contacts::save(int scId, int ecId, const QVariantMap ¶ms) { + QContact result; + QList 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() << + 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() << + 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 > 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 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 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 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 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 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 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 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(", ")); +}