diff -r e686773b3f54 -r 0ba2181d7c28 qtcontactsmobility/src/versit/qversitcontactimporter_p.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/qtcontactsmobility/src/versit/qversitcontactimporter_p.cpp Fri Mar 19 09:27:18 2010 +0200 @@ -0,0 +1,634 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Mobility Components. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qversitdefs.h" +#include "qversitcontactimporter_p.h" +#include "qversitdocument.h" +#include "qversitproperty.h" +#include "qmobilityglobal.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +QTM_BEGIN_NAMESPACE + +/*! + * Constructor. + */ +QVersitContactImporterPrivate::QVersitContactImporterPrivate() +{ + // Contact detail mappings + int versitPropertyCount = + sizeof(versitContactDetailMappings)/sizeof(versitContactDetailMapping); + for (int i=0; i < versitPropertyCount; i++) { + QString versitPropertyName = + QString::fromAscii(versitContactDetailMappings[i].versitPropertyName); + QPair contactDetail; + contactDetail.first = + QString::fromAscii(versitContactDetailMappings[i].contactDetailDefinitionName); + contactDetail.second = + QString::fromAscii(versitContactDetailMappings[i].contactDetailValueKey); + mDetailMappings.insert(versitPropertyName,contactDetail); + } + + // Context mappings + int contextCount = sizeof(versitContextMappings)/sizeof(versitMapping); + for (int i=0; i < contextCount; i++) { + mContextMappings.insert( + QString::fromAscii(versitContextMappings[i].versitString), + QString::fromAscii(versitContextMappings[i].contactString)); + } + + // Subtype mappings + int subTypeCount = sizeof(versitSubTypeMappings)/sizeof(versitMapping); + for (int i=0; i < subTypeCount; i++) { + mSubTypeMappings.insert( + QString::fromAscii(versitSubTypeMappings[i].versitString), + QString::fromAscii(versitSubTypeMappings[i].contactString)); + } + + // File extension mappings + int fileExtensionCount = sizeof(versitFileExtensionMappings)/sizeof(versitMapping); + for (int i=0; i < fileExtensionCount; i++) { + mFileExtensionMappings.insert( + QString::fromAscii(versitFileExtensionMappings[i].versitString), + QString::fromAscii(versitFileExtensionMappings[i].contactString)); + } +} + +/*! + * Destructor. + */ +QVersitContactImporterPrivate::~QVersitContactImporterPrivate() +{ +} + +/*! + * Generates a QContact from \a versitDocument. + */ +QContact QVersitContactImporterPrivate::importContact( + const QVersitDocument& versitDocument) +{ + mUnknownVersitProperties.clear(); + QContact contact; + const QList properties = versitDocument.properties(); + foreach (QVersitProperty property, properties) { + QPair detailDefinition = + mDetailMappings.value(property.name()); + QString detailDefinitionName = detailDefinition.first; + QContactDetail* detail = 0; + if (detailDefinitionName == QContactAddress::DefinitionName) { + detail = createAddress(property); + } else if (detailDefinitionName == QContactName::DefinitionName) { + detail = createName(property,contact); + } else if (detailDefinitionName == QContactBirthday::DefinitionName) { + detail = createBirthday(property); + } else if (detailDefinitionName == QContactGeolocation::DefinitionName){ + detail = createGeoLocation(property); + } else if (detailDefinitionName == QContactOrganization::DefinitionName) { + detail = createOrganization(property,contact); + } else if (detailDefinitionName == QContactNickname::DefinitionName) { + createNicknames(property,contact); + } else if (detailDefinitionName == QContactAvatar::DefinitionName) { + detail = createAvatar(property,versitDocument,detailDefinition.second); + } else if (detailDefinitionName == QContactTimestamp::DefinitionName) { + detail = createTimeStamp(property); + } else if (detailDefinitionName == QContactPhoneNumber::DefinitionName) { + detail = createPhone(property); + } else if (detailDefinitionName == QContactAnniversary::DefinitionName) { + detail = createAnniversary(property); + } else if (detailDefinitionName == QContactFamily::DefinitionName) { + detail = createFamily(property,contact); + } else if (detailDefinitionName == QContactOnlineAccount::DefinitionName) { + detail = createOnlineAccount(property); + } else if (detailDefinitionName == QContactDisplayLabel::DefinitionName) { + detail = createLabel(property, contact); + } else { + detail = createNameValueDetail(property); + if (!detail) + mUnknownVersitProperties.append(property); + } + + if (detail) { + QStringList contexts(extractContexts(property)); + if (!contexts.empty()) + detail->setContexts(contexts); + contact.saveDetail(detail); + delete detail; + } + } + + return contact; +} + +/*! + * Creates a QContactName from \a property + */ +QContactDetail* QVersitContactImporterPrivate::createName( + const QVersitProperty& property,const QContact& contact) const +{ + QContactName* name = 0; + QContactDetail detail = contact.detail(QContactName::DefinitionName); + if (!detail.isEmpty()) { + name = new QContactName(static_cast(detail)); + // If multiple name properties exist, + // discard all except the first occurence + if (!name->first().isEmpty()) { + return 0; + } + } else { + name = new QContactName(); + } + + QList values = property.value().split(';'); + name->setLast(takeFirst(values)); + name->setFirst(takeFirst(values)); + name->setMiddle(takeFirst(values)); + name->setPrefix(takeFirst(values)); + name->setSuffix(takeFirst(values)); + return name; +} + +/*! + * Creates a QContactPhoneNumber from \a property + */ +QContactDetail* QVersitContactImporterPrivate::createPhone( + const QVersitProperty& property) const +{ + QContactPhoneNumber* phone = new QContactPhoneNumber(); + phone->setNumber(QString::fromAscii(property.value())); + phone->setSubTypes(extractSubTypes(property)); + return phone; +} + +/*! + * Creates a QContactAddress from \a property + */ +QContactDetail* QVersitContactImporterPrivate::createAddress( + const QVersitProperty& property) const +{ + QContactAddress* address = new QContactAddress(); + + QList addressParts = property.value().split(';'); + address->setPostOfficeBox(takeFirst(addressParts)); + // There is no setter for the Extended Address in QContactAddress: + if (!addressParts.isEmpty()) + addressParts.removeFirst(); + address->setStreet(takeFirst(addressParts)); + address->setLocality(takeFirst(addressParts)); + address->setRegion(takeFirst(addressParts)); + address->setPostcode(takeFirst(addressParts)); + address->setCountry(takeFirst(addressParts)); + + address->setSubTypes(extractSubTypes(property)); + + return address; +} + +/*! + * Creates a QContactOrganization from \a property + */ +QContactDetail* QVersitContactImporterPrivate::createOrganization( + const QVersitProperty& property, + const QContact& contact) const +{ + QContactOrganization* organization = 0; + QPair detailNameAndFieldName = + mDetailMappings.value(property.name()); + QString fieldName = detailNameAndFieldName.second; + QList organizations = + contact.details(QContactOrganization::DefinitionName); + foreach(QContactDetail detail, organizations) { + QContactOrganization current = static_cast(detail); + if (current.value(fieldName).length() == 0) { + organization = new QContactOrganization(current); + break; + } + } + if (!organization) { + organization = new QContactOrganization(); + } + if (fieldName == QContactOrganization::FieldName) { + setOrganizationNames(*organization,property); + } else if (fieldName == QContactOrganization::FieldTitle) { + organization->setTitle(QString::fromAscii(property.value())); + } else if (fieldName == QContactOrganization::FieldRole) { + organization->setRole(QString::fromAscii(property.value())); + } else if (fieldName == QContactOrganization::FieldLogo) { + setOrganizationLogo(*organization,property); + } else if (fieldName == QContactOrganization::FieldAssistantName) { + organization->setAssistantName(QString::fromAscii(property.value())); + } else { + delete organization; + organization = 0; + } + return organization; +} + +/*! + * Set the organization name and department(s) from \a property. + */ +void QVersitContactImporterPrivate::setOrganizationNames( + QContactOrganization& organization, + const QVersitProperty& property) const +{ + QByteArray value = property.value(); + int firstSemicolon = value.indexOf(";"); + if (firstSemicolon >= 0) { + organization.setName(QString::fromAscii(value.left(firstSemicolon))); + QString departmentsStr(QString::fromAscii(value.mid(firstSemicolon+1))); + QStringList departments = + departmentsStr.split(QString::fromAscii(";"),QString::SkipEmptyParts); + organization.setDepartment(departments); + } else { + organization.setName(QString::fromAscii(value)); + } +} + +/*! + * Set the organization logo from \a property. + */ +void QVersitContactImporterPrivate::setOrganizationLogo( + QContactOrganization& org, + const QVersitProperty& property) const +{ + QString value(QString::fromAscii(property.value())); + + const QString valueParam = + property.parameters().value(QString::fromAscii("VALUE")); + + if (valueParam != QString::fromAscii("URL")) { + QString path(mImagePath); + if (!path.endsWith(QString::fromAscii("/"))) + path += QString::fromAscii("/"); + // Let saveContentToFile to generate a random string as the name + value = saveContentToFile(path,property); + } + + org.setLogo(value); +} + +/*! + * Creates a QContactTimeStamp from \a property + */ +QContactDetail* QVersitContactImporterPrivate::createTimeStamp( + const QVersitProperty& property) const +{ + QContactTimestamp* timeStamp = new QContactTimestamp(); + QByteArray value(property.value()); + bool utc = (value.endsWith("Z") || value.endsWith("z")); + if (utc) + value.chop(1); // take away z from end; + + QDateTime dateTime = parseDateTime(value,"yyyyMMddThhmmss"); + if (utc) + dateTime.setTimeSpec(Qt::UTC); + timeStamp->setLastModified(dateTime); + return timeStamp; +} + +/*! + * Creates a QContactAnniversary from \a property + */ +QContactDetail* QVersitContactImporterPrivate::createAnniversary( + const QVersitProperty& property) const +{ + QContactAnniversary* anniversary = new QContactAnniversary(); + QDateTime dateTime = + parseDateTime(property.value(),"yyyyMMdd"); + anniversary->setOriginalDate(dateTime.date()); + return anniversary; +} + +/*! + * Creates a QContactBirthday from \a property + */ +QContactDetail* QVersitContactImporterPrivate::createBirthday( + const QVersitProperty& property) const +{ + QContactBirthday* bday = new QContactBirthday(); + QDateTime dateTime = + parseDateTime(property.value(),"yyyyMMdd"); + bday->setDate(dateTime.date()); + return bday; +} + +/*! + * Creates QContactNicknames from \a property and adds them to \a contact + */ +void QVersitContactImporterPrivate::createNicknames( + const QVersitProperty& property, + QContact& contact) const +{ + QList values = property.value().split(','); + foreach(QByteArray value,values) { + QContactNickname* nickName = new QContactNickname(); + nickName->setNickname(QString::fromAscii(value)); + contact.saveDetail(nickName); + delete nickName; + } +} + +/*! + * Creates a QContactOnlineAccount from \a property + */ +QContactDetail* QVersitContactImporterPrivate::createOnlineAccount( + const QVersitProperty& property) const +{ + QContactOnlineAccount* onlineAccount = new QContactOnlineAccount(); + onlineAccount->setAccountUri(QString::fromAscii(property.value())); + if (property.name() == QString::fromAscii("X-SIP")) { + QStringList subTypes = extractSubTypes(property); + if (subTypes.count() == 0) + subTypes.append(QContactOnlineAccount::SubTypeSip); + onlineAccount->setSubTypes(subTypes); + } + else if (property.name() == QString::fromAscii("X-IMPP") || + property.name() == QString::fromAscii("IMPP")) { + onlineAccount->setSubTypes(QContactOnlineAccount::SubTypeImpp); + } + else { + // NOP + } + return onlineAccount; +} + +/*! + * Creates a QContactAvatar from \a property + */ +QContactDetail* QVersitContactImporterPrivate::createAvatar( + const QVersitProperty& property, + const QVersitDocument& versitDocument, + const QString& subType) const +{ + QString value(QString::fromAscii(property.value())); + + const QString valueParam = + property.parameters().value(QString::fromAscii("VALUE")); + + if (valueParam != QString::fromAscii("URL")) { + QString pathAndName(mImagePath); + if (subType == QContactAvatar::SubTypeAudioRingtone) + pathAndName = mAudioClipPath; + if (!pathAndName.endsWith(QString::fromAscii("/"))) + pathAndName += QString::fromAscii("/"); + pathAndName += getFirstAndLastName(versitDocument); + value = saveContentToFile(pathAndName,property); + } + + QContactAvatar* avatar = 0; + if (!value.isEmpty()) { + avatar = new QContactAvatar(); + avatar->setAvatar(value); + avatar->setSubType(subType); + } + return avatar; +} + +/*! + * Creates a QContactGeolocation from \a property + */ +QContactDetail* QVersitContactImporterPrivate::createGeoLocation( + const QVersitProperty& property) const +{ + QContactGeolocation* geo = new QContactGeolocation(); + QList values = property.value().split(','); + geo->setLongitude(takeFirst(values).toDouble()); + geo->setLatitude(takeFirst(values).toDouble()); + return geo; +} + +/*! + * Creates a QContactFamily from \a property + */ +QContactDetail* QVersitContactImporterPrivate::createFamily( + const QVersitProperty& property, + const QContact& contact) const +{ + QString val = QString::fromAscii(property.value()); + QContactFamily family = + static_cast(contact.detail(QContactFamily::DefinitionName)); + if (property.name() == QString::fromAscii("X-SPOUSE")) { + family.setSpouse(val); + } else if (property.name() == QString::fromAscii("X-CHILDREN")) { + family.setChildren(val.split(QString::fromAscii(","))); + } + return new QContactDetail(family); +} + +/*! + * Creates a simple name-value contact detail. + */ +QContactDetail* QVersitContactImporterPrivate::createNameValueDetail( + const QVersitProperty& property) const +{ + QContactDetail* detail = 0; + QPair nameAndValueType = + mDetailMappings.value(property.name()); + if (nameAndValueType.first.length() > 0) { + detail = new QContactDetail(nameAndValueType.first); + detail->setValue( + nameAndValueType.second,QString::fromAscii(property.value())); + } + return detail; +} + +/*! + * Creates a simple name-value contact detail. + */ +QContactDetail* QVersitContactImporterPrivate::createLabel( + const QVersitProperty& property, + const QContact& contact) const +{ + QContactName* name = 0; + QContactDetail detail = contact.detail(QContactName::DefinitionName); + if (!detail.isEmpty()) { + name = new QContactName(static_cast(detail)); + } else { + name = new QContactName(); + } + + // Setting the QContactDisplayLabel is done by the backend + name->setCustomLabel(QString::fromAscii(property.value())); + return name; +} + +/*! + * Extracts the list of contexts from \a types + */ +QStringList QVersitContactImporterPrivate::extractContexts( + const QVersitProperty& property) const +{ + QStringList types = + property.parameters().values(QString::fromAscii("TYPE")); + QStringList contexts; + foreach (QString type, types) { + QString value = mContextMappings.value(type); + if (value.length() > 0) + contexts.append(value); + } + return contexts; +} + +/*! + * Extracts the list of subtypes from \a property + */ +QStringList QVersitContactImporterPrivate::extractSubTypes( + const QVersitProperty& property) const +{ + QStringList types = + property.parameters().values(QString::fromAscii("TYPE")); + QStringList subTypes; + foreach (QString type, types) { + QString subType = mSubTypeMappings.value(type); + if (subType.length() > 0) + subTypes += subType; + } + return subTypes; +} + +/*! + * Takes the first value in \a list and converts it to a QString. + * An empty QString is returned, if the list is empty. + */ +QString QVersitContactImporterPrivate::takeFirst(QList& list) const +{ + QString first; + if (!list.isEmpty()) + first = QString::fromAscii(list.takeFirst()); + return first; +} + +/*! + * Parses a date and time from text + */ +QDateTime QVersitContactImporterPrivate::parseDateTime( + const QByteArray& text, + const QByteArray& format) const +{ + QDateTime dateTime; + QString value(QString::fromAscii(text)); + if (text.contains("-")) { + dateTime = QDateTime::fromString(value,Qt::ISODate); + } else { + dateTime = QDateTime::fromString(value, QString::fromAscii(format)); + } + return dateTime; +} + +/*! + * Save the value of the \a property to a file with name \a pathAndName. + */ +QString QVersitContactImporterPrivate::saveContentToFile( + const QString& pathAndName, + const QVersitProperty& property) const +{ + QString encoding = + property.parameters().value(QString::fromAscii("ENCODING")); + QByteArray content = property.value(); + + QString type = + property.parameters().value(QString::fromAscii("TYPE")); + // Use the type parameter value as it is, if not found in the mapping table + QString extension = mFileExtensionMappings.value(type,type); + + QString fileName(pathAndName); + fileName += QString::number(qrand()); + fileName += QString::fromAscii("."); + fileName += extension.toLower(); + + QFile file(fileName); + qint64 writeResult = -1; + if (file.open(QIODevice::WriteOnly)) { + if (encoding == QString::fromAscii("BASE64") || + encoding == QString::fromAscii("B")) { + writeResult = file.write(QByteArray::fromBase64(property.value())); + } else { + // default assumption + // quoted-printable encoding is parsed already in the reader + writeResult = file.write(property.value()); + } + } + file.close(); + return (writeResult > 0) ? fileName : QString(); +} + +/*! + * Extracts the first and last name from \a document to a string. + */ +QString QVersitContactImporterPrivate::getFirstAndLastName( + const QVersitDocument& document) const +{ + QString name; + const QList properties = document.properties(); + foreach(const QVersitProperty& nameProperty, properties) { + if (nameProperty.name() == QString::fromAscii("N")) { + QList values = nameProperty.value().split(';'); + name.append(takeFirst(values)); + name.append(takeFirst(values)); + break; + } + } + return name; +} + +QTM_END_NAMESPACE