src/versit/qversitcontactimporter_p.cpp
changeset 0 876b1a06bc25
child 5 603d3f8b6302
equal deleted inserted replaced
-1:000000000000 0:876b1a06bc25
       
     1 /****************************************************************************
       
     2 **
       
     3 ** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
       
     4 ** All rights reserved.
       
     5 ** Contact: Nokia Corporation (qt-info@nokia.com)
       
     6 **
       
     7 ** This file is part of the Qt Mobility Components.
       
     8 **
       
     9 ** $QT_BEGIN_LICENSE:LGPL$
       
    10 ** No Commercial Usage
       
    11 ** This file contains pre-release code and may not be distributed.
       
    12 ** You may use this file in accordance with the terms and conditions
       
    13 ** contained in the Technology Preview License Agreement accompanying
       
    14 ** this package.
       
    15 **
       
    16 ** GNU Lesser General Public License Usage
       
    17 ** Alternatively, this file may be used under the terms of the GNU Lesser
       
    18 ** General Public License version 2.1 as published by the Free Software
       
    19 ** Foundation and appearing in the file LICENSE.LGPL included in the
       
    20 ** packaging of this file.  Please review the following information to
       
    21 ** ensure the GNU Lesser General Public License version 2.1 requirements
       
    22 ** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
       
    23 **
       
    24 ** In addition, as a special exception, Nokia gives you certain additional
       
    25 ** rights.  These rights are described in the Nokia Qt LGPL Exception
       
    26 ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
       
    27 **
       
    28 ** If you have questions regarding the use of this file, please contact
       
    29 ** Nokia at qt-info@nokia.com.
       
    30 **
       
    31 **
       
    32 **
       
    33 **
       
    34 **
       
    35 **
       
    36 **
       
    37 **
       
    38 ** $QT_END_LICENSE$
       
    39 **
       
    40 ****************************************************************************/
       
    41 
       
    42 #include "qversitdefs_p.h"
       
    43 #include "qversitcontactimporter_p.h"
       
    44 #include "qversitdocument.h"
       
    45 #include "qversitproperty.h"
       
    46 #include "qmobilityglobal.h"
       
    47 
       
    48 #include <qcontactmanagerengine.h>
       
    49 #include <qcontact.h>
       
    50 #include <qcontactdetail.h>
       
    51 #include <qcontactname.h>
       
    52 #include <qcontactphonenumber.h>
       
    53 #include <qcontactaddress.h>
       
    54 #include <qcontactemailaddress.h>
       
    55 #include <qcontactorganization.h>
       
    56 #include <qcontacturl.h>
       
    57 #include <qcontactguid.h>
       
    58 #include <qcontacttimestamp.h>
       
    59 #include <qcontactanniversary.h>
       
    60 #include <qcontactbirthday.h>
       
    61 #include <qcontactgender.h>
       
    62 #include <qcontactnickname.h>
       
    63 #include <qcontactavatar.h>
       
    64 #include <qcontactgeolocation.h>
       
    65 #include <qcontactnote.h>
       
    66 #include <qcontactonlineaccount.h>
       
    67 #include <qcontactfamily.h>
       
    68 #include <qcontactdisplaylabel.h>
       
    69 #include <qcontactthumbnail.h>
       
    70 #include <qcontactringtone.h>
       
    71 
       
    72 #include <QHash>
       
    73 #include <QFile>
       
    74 
       
    75 QTM_USE_NAMESPACE
       
    76 
       
    77 /*!
       
    78  * Constructor.
       
    79  */
       
    80 QVersitContactImporterPrivate::QVersitContactImporterPrivate() :
       
    81     mPropertyHandler(NULL),
       
    82     mPropertyHandler2(NULL),
       
    83     mPropertyHandlerVersion(0),
       
    84     mDefaultResourceHandler(new QVersitDefaultResourceHandler),
       
    85     mResourceHandler(mDefaultResourceHandler)
       
    86 {
       
    87     // Contact detail mappings
       
    88     int versitPropertyCount =
       
    89         sizeof(versitContactDetailMappings)/sizeof(VersitContactDetailMapping);
       
    90     for (int i=0; i < versitPropertyCount; i++) {
       
    91         QString versitPropertyName =
       
    92             QLatin1String(versitContactDetailMappings[i].versitPropertyName);
       
    93         QPair<QString,QString> contactDetail;
       
    94         contactDetail.first =
       
    95             QLatin1String(versitContactDetailMappings[i].contactDetailDefinitionName);
       
    96         contactDetail.second =
       
    97             QLatin1String(versitContactDetailMappings[i].contactDetailValueKey);
       
    98         mDetailMappings.insert(versitPropertyName,contactDetail);
       
    99     }
       
   100 
       
   101     // Context mappings
       
   102     int contextCount = sizeof(versitContextMappings)/sizeof(VersitMapping);
       
   103     for (int i=0; i < contextCount; i++) {
       
   104         mContextMappings.insert(
       
   105             QLatin1String(versitContextMappings[i].versitString),
       
   106             QLatin1String(versitContextMappings[i].contactString));
       
   107     }
       
   108 
       
   109     // Subtype mappings
       
   110     int subTypeCount = sizeof(versitSubTypeMappings)/sizeof(VersitMapping);
       
   111     for (int i=0; i < subTypeCount; i++) {
       
   112         mSubTypeMappings.insert(
       
   113             QLatin1String(versitSubTypeMappings[i].versitString),
       
   114             QLatin1String(versitSubTypeMappings[i].contactString));
       
   115     }
       
   116 }
       
   117 
       
   118 /*!
       
   119  * Destructor.
       
   120  */
       
   121 QVersitContactImporterPrivate::~QVersitContactImporterPrivate()
       
   122 {
       
   123     delete mDefaultResourceHandler;
       
   124 }
       
   125 
       
   126 /*!
       
   127  * Generates a QContact from \a versitDocument.
       
   128  */
       
   129 bool QVersitContactImporterPrivate::importContact(
       
   130         const QVersitDocument& document, int contactIndex, QContact* contact,
       
   131         QVersitContactImporter::Error* error)
       
   132 {
       
   133     if (document.type() != QVersitDocument::VCard21Type
       
   134         && document.type() != QVersitDocument::VCard30Type) {
       
   135         *error = QVersitContactImporter::InvalidDocumentError;
       
   136         return false;
       
   137     }
       
   138     const QList<QVersitProperty> properties = document.properties();
       
   139     if (properties.size() == 0) {
       
   140         *error = QVersitContactImporter::EmptyDocumentError;
       
   141         return false;
       
   142     }
       
   143 
       
   144     // First, do the properties with PREF set so they appear first in the contact details
       
   145     foreach (const QVersitProperty& property, properties) {
       
   146         QStringList typeParameters = property.parameters().values(QLatin1String("TYPE"));
       
   147         if (typeParameters.contains(QLatin1String("PREF"), Qt::CaseInsensitive))
       
   148             importProperty(document, property, contactIndex, contact);
       
   149     }
       
   150     // ... then, do the rest of the properties.
       
   151     foreach (const QVersitProperty& property, properties) {
       
   152         QStringList typeParameters = property.parameters().values(QLatin1String("TYPE"));
       
   153         if (!typeParameters.contains(QLatin1String("PREF"), Qt::CaseInsensitive))
       
   154             importProperty(document, property, contactIndex, contact);
       
   155     }
       
   156 
       
   157     contact->setType(QContactType::TypeContact);
       
   158     QContactManagerEngine::setContactDisplayLabel(contact, QVersitContactImporterPrivate::synthesizedDisplayLabel(*contact));
       
   159 
       
   160     if (mPropertyHandler2 && mPropertyHandlerVersion > 1) {
       
   161         mPropertyHandler2->documentProcessed(document, contact);
       
   162     }
       
   163 
       
   164     return true;
       
   165 }
       
   166 
       
   167 void QVersitContactImporterPrivate::importProperty(
       
   168         const QVersitDocument& document, const QVersitProperty& property, int contactIndex,
       
   169         QContact* contact)
       
   170 {
       
   171     if (mPropertyHandler
       
   172         && mPropertyHandlerVersion == 1
       
   173         && mPropertyHandler->preProcessProperty(document, property, contactIndex, contact))
       
   174         return;
       
   175 
       
   176     QPair<QString,QString> detailDefinition =
       
   177         mDetailMappings.value(property.name());
       
   178     QString detailDefinitionName = detailDefinition.first;
       
   179 
       
   180     QList<QContactDetail> updatedDetails;
       
   181 
       
   182     bool success = false;
       
   183 
       
   184     // The following functions create and save the details to the contact
       
   185     if (detailDefinitionName == QContactAddress::DefinitionName) {
       
   186         success = createAddress(property, contact, &updatedDetails); // pass in group
       
   187     } else if (detailDefinitionName == QContactName::DefinitionName) {
       
   188         success = createName(property, contact, &updatedDetails);
       
   189     } else if (detailDefinitionName == QContactBirthday::DefinitionName) {
       
   190         success = createBirthday(property, contact, &updatedDetails);
       
   191     } else if (detailDefinitionName == QContactGeoLocation::DefinitionName){
       
   192         success = createGeoLocation(property, contact, &updatedDetails);
       
   193     } else if (detailDefinitionName == QContactOrganization::DefinitionName) {
       
   194         success = createOrganization(property, contact, &updatedDetails);
       
   195     } else if (detailDefinitionName == QContactNickname::DefinitionName) {
       
   196         success = createNicknames(property, contact, &updatedDetails);
       
   197     } else if (detailDefinitionName == QContactRingtone::DefinitionName) {
       
   198         success = createRingtone(property, contact, &updatedDetails);
       
   199     } else if (detailDefinitionName == QContactThumbnail::DefinitionName) {
       
   200         success = createThumbnail(property, contact, &updatedDetails);
       
   201     } else if (detailDefinitionName == QContactTimestamp::DefinitionName) {
       
   202         success = createTimeStamp(property, contact, &updatedDetails);
       
   203     } else if (detailDefinitionName == QContactPhoneNumber::DefinitionName) {
       
   204         success = createPhone(property, contact, &updatedDetails);
       
   205     } else if (detailDefinitionName == QContactAnniversary::DefinitionName) {
       
   206         success = createAnniversary(property, contact, &updatedDetails);
       
   207     } else if (detailDefinitionName == QContactFamily::DefinitionName) {
       
   208         success = createFamily(property, contact, &updatedDetails);
       
   209     } else if (detailDefinitionName == QContactOnlineAccount::DefinitionName) {
       
   210         success = createOnlineAccount(property, contact, &updatedDetails);
       
   211     } else if (detailDefinitionName == QContactTag::DefinitionName) {
       
   212         success = createTags(property, contact, &updatedDetails);
       
   213     } else if (detailDefinitionName == QContactDisplayLabel::DefinitionName) {
       
   214         success = createCustomLabel(property, contact, &updatedDetails);
       
   215     } else {
       
   216         // Look up mDetailMappings for a simple mapping from property to detail.
       
   217         success = createNameValueDetail(property, contact, &updatedDetails);
       
   218     }
       
   219 
       
   220     if (mPropertyHandler2 && mPropertyHandlerVersion > 1) {
       
   221         mPropertyHandler2->propertyProcessed(document, property, success, *contact, &updatedDetails);
       
   222     }
       
   223 
       
   224     foreach (QContactDetail detail, updatedDetails) {
       
   225         contact->saveDetail(&detail);
       
   226     }
       
   227 
       
   228     if (mPropertyHandler && mPropertyHandlerVersion == 1)
       
   229         mPropertyHandler->postProcessProperty(document, property, success, contactIndex, contact);
       
   230 }
       
   231 /*!
       
   232  * Creates a QContactName from \a property
       
   233  */
       
   234 bool QVersitContactImporterPrivate::createName(
       
   235     const QVersitProperty& property,
       
   236     QContact* contact,
       
   237     QList<QContactDetail>* updatedDetails)
       
   238 {
       
   239     QContactName name;
       
   240     QContactDetail detail = contact->detail(QContactName::DefinitionName);
       
   241     if (!detail.isEmpty()) {
       
   242         // If multiple name properties exist,
       
   243         // discard all except the first occurrence
       
   244         if (!detail.value(QContactName::FieldFirstName).isEmpty())
       
   245             return false;
       
   246         else
       
   247             name = QContactName(static_cast<QContactName>(detail));
       
   248     }
       
   249 
       
   250     QVariant variant = property.variantValue();
       
   251     if (property.valueType() != QVersitProperty::CompoundType
       
   252             || variant.type() != QVariant::StringList)
       
   253         return false;
       
   254     QStringList values = variant.toStringList();
       
   255     QString value(takeFirst(values));
       
   256     if (!value.isEmpty())
       
   257         name.setLastName(value);
       
   258     value = takeFirst(values);
       
   259     if (!value.isEmpty())
       
   260         name.setFirstName(value);
       
   261     value = takeFirst(values);
       
   262     if (!value.isEmpty())
       
   263         name.setMiddleName(value);
       
   264     value = takeFirst(values);
       
   265     if (!value.isEmpty())
       
   266         name.setPrefix(value);
       
   267     value = takeFirst(values);
       
   268     if (!value.isEmpty())
       
   269         name.setSuffix(value);
       
   270 
       
   271     saveDetailWithContext(updatedDetails, name, extractContexts(property));
       
   272     return true;
       
   273 }
       
   274 
       
   275 /*!
       
   276  * Creates a QContactPhoneNumber from \a property
       
   277  */
       
   278 bool QVersitContactImporterPrivate::createPhone(
       
   279     const QVersitProperty& property,
       
   280     QContact* contact,
       
   281     QList<QContactDetail>* updatedDetails)
       
   282 {
       
   283     Q_UNUSED(contact)
       
   284     QContactPhoneNumber phone;
       
   285     QString value(property.value());
       
   286     if (value.isEmpty())
       
   287         return false;
       
   288     phone.setNumber(property.value());
       
   289     QStringList subTypes(extractSubTypes(property));
       
   290     if (property.name() == QLatin1String("X-ASSISTANT-TEL"))
       
   291         subTypes << QContactPhoneNumber::SubTypeAssistant;
       
   292     if (!subTypes.isEmpty())
       
   293         phone.setSubTypes(subTypes);
       
   294 
       
   295     saveDetailWithContext(updatedDetails, phone, extractContexts(property));
       
   296     return true;
       
   297 }
       
   298 
       
   299 /*!
       
   300  * Creates a QContactAddress from \a property
       
   301  */
       
   302 bool QVersitContactImporterPrivate::createAddress(
       
   303     const QVersitProperty& property,
       
   304     QContact* contact,
       
   305     QList<QContactDetail>* updatedDetails)
       
   306 {
       
   307     Q_UNUSED(contact)
       
   308     QContactAddress address;
       
   309 
       
   310     QVariant variant = property.variantValue();
       
   311     if (property.valueType() != QVersitProperty::CompoundType
       
   312             || variant.type() != QVariant::StringList)
       
   313         return false;
       
   314     QStringList addressParts = variant.toStringList();
       
   315     QString value(takeFirst(addressParts));
       
   316     if (!value.isEmpty())
       
   317         address.setPostOfficeBox(value);
       
   318     // There is no setter for the Extended Address in QContactAddress:
       
   319     if (!addressParts.isEmpty())
       
   320         addressParts.removeFirst();
       
   321     value = takeFirst(addressParts);
       
   322     if (!value.isEmpty())
       
   323         address.setStreet(value);
       
   324     value = takeFirst(addressParts);
       
   325     if (!value.isEmpty())
       
   326         address.setLocality(value);
       
   327     value = takeFirst(addressParts);
       
   328     if (!value.isEmpty())
       
   329         address.setRegion(value);
       
   330     value = takeFirst(addressParts);
       
   331     if (!value.isEmpty())
       
   332         address.setPostcode(value);
       
   333     value = takeFirst(addressParts);
       
   334     if (!value.isEmpty())
       
   335         address.setCountry(value);
       
   336     QStringList subTypes(extractSubTypes(property));
       
   337     if (!subTypes.isEmpty())
       
   338         address.setSubTypes(subTypes);
       
   339 
       
   340     saveDetailWithContext(updatedDetails, address, extractContexts(property));
       
   341     return true;
       
   342 }
       
   343 
       
   344 /*!
       
   345  * Creates a QContactOrganization from \a property
       
   346  */
       
   347 bool QVersitContactImporterPrivate::createOrganization(
       
   348     const QVersitProperty& property,
       
   349     QContact* contact,
       
   350     QList<QContactDetail>* updatedDetails)
       
   351 {
       
   352     QContactOrganization organization;
       
   353     QPair<QString,QString> detailNameAndFieldName =
       
   354         mDetailMappings.value(property.name());
       
   355     QString fieldName = detailNameAndFieldName.second;
       
   356     QList<QContactOrganization> organizations = contact->details<QContactOrganization>();
       
   357     foreach(const QContactOrganization& current, organizations) {
       
   358         if (current.value(fieldName).length() == 0) {
       
   359             organization = current;
       
   360             break;
       
   361         }
       
   362     }
       
   363     if (fieldName == QContactOrganization::FieldName) {
       
   364         setOrganizationNames(organization, property);
       
   365     } else if (fieldName == QContactOrganization::FieldTitle) {
       
   366         organization.setTitle(property.value());
       
   367     } else if (fieldName == QContactOrganization::FieldRole) {
       
   368         organization.setRole(property.value());
       
   369     } else if (fieldName == QContactOrganization::FieldLogoUrl) {
       
   370         setOrganizationLogo(organization, property);
       
   371     } else if (fieldName == QContactOrganization::FieldAssistantName) {
       
   372         organization.setAssistantName(property.value());
       
   373     } else {
       
   374         return false;
       
   375     }
       
   376 
       
   377     saveDetailWithContext(updatedDetails, organization, extractContexts(property));
       
   378     return true;
       
   379 }
       
   380 
       
   381 /*!
       
   382  * Set the organization name and department(s) from \a property.
       
   383  */
       
   384 void QVersitContactImporterPrivate::setOrganizationNames(
       
   385     QContactOrganization& organization, const QVersitProperty& property) const
       
   386 {
       
   387     QVariant variant = property.variantValue();
       
   388     if (property.valueType() == QVersitProperty::CompoundType
       
   389         && variant.type() == QVariant::StringList) {
       
   390         QStringList values = variant.toStringList();
       
   391         QString name(takeFirst(values));
       
   392         if (!name.isEmpty())
       
   393             organization.setName(name);
       
   394         if (!values.isEmpty())
       
   395             organization.setDepartment(values);
       
   396     }
       
   397 }
       
   398 
       
   399 /*!
       
   400  * Set the organization logo from \a property.
       
   401  */
       
   402 void QVersitContactImporterPrivate::setOrganizationLogo(
       
   403     QContactOrganization& org, const QVersitProperty& property) const
       
   404 {
       
   405     QString location;
       
   406     QByteArray data;
       
   407     saveDataFromProperty(property, &location, &data);
       
   408     if (!location.isEmpty())
       
   409         org.setLogoUrl(QUrl(location));
       
   410 }
       
   411 
       
   412 /*!
       
   413  * Creates a QContactTimeStamp from \a property
       
   414  */
       
   415 bool QVersitContactImporterPrivate::createTimeStamp(
       
   416     const QVersitProperty& property,
       
   417     QContact* contact,
       
   418     QList<QContactDetail>* updatedDetails)
       
   419 {
       
   420     Q_UNUSED(contact)
       
   421     QContactTimestamp timeStamp;
       
   422     QString value(property.value());
       
   423     bool utc = value.endsWith(QLatin1Char('Z'), Qt::CaseInsensitive);
       
   424     if (utc)
       
   425         value.chop(1); // take away z from end;
       
   426 
       
   427     QDateTime dateTime = parseDateTime(value,QLatin1String("yyyyMMddThhmmss"));
       
   428     if (!dateTime.isValid())
       
   429         return false;
       
   430     if (utc)
       
   431         dateTime.setTimeSpec(Qt::UTC);
       
   432     timeStamp.setLastModified(dateTime);
       
   433     saveDetailWithContext(updatedDetails, timeStamp, extractContexts(property));
       
   434     return true;
       
   435 }
       
   436 
       
   437 /*!
       
   438  * Creates a QContactAnniversary from \a property
       
   439  */
       
   440 bool QVersitContactImporterPrivate::createAnniversary(
       
   441     const QVersitProperty& property,
       
   442     QContact* contact,
       
   443     QList<QContactDetail>* updatedDetails)
       
   444 {
       
   445     Q_UNUSED(contact)
       
   446     QContactAnniversary anniversary;
       
   447     QDateTime dateTime = parseDateTime(property.value(), QLatin1String("yyyyMMdd"));
       
   448     if (!dateTime.isValid())
       
   449         return false;
       
   450     anniversary.setOriginalDate(dateTime.date());
       
   451     saveDetailWithContext(updatedDetails, anniversary, extractContexts(property));
       
   452     return true;
       
   453 }
       
   454 
       
   455 /*!
       
   456  * Creates a QContactBirthday from \a property
       
   457  */
       
   458 bool QVersitContactImporterPrivate::createBirthday(
       
   459     const QVersitProperty& property,
       
   460     QContact* contact,
       
   461     QList<QContactDetail>* updatedDetails)
       
   462 {
       
   463     Q_UNUSED(contact)
       
   464     QContactBirthday bday;
       
   465     QDateTime dateTime = parseDateTime(property.value(), QLatin1String("yyyyMMdd"));
       
   466     if (!dateTime.isValid())
       
   467         return false;
       
   468     bday.setDate(dateTime.date());
       
   469     saveDetailWithContext(updatedDetails, bday, extractContexts(property));
       
   470     return true;
       
   471 }
       
   472 
       
   473 /*!
       
   474  * Creates QContactNicknames from \a property
       
   475  */
       
   476 bool QVersitContactImporterPrivate::createNicknames(
       
   477     const QVersitProperty& property,
       
   478     QContact* contact,
       
   479     QList<QContactDetail>* updatedDetails)
       
   480 {
       
   481     Q_UNUSED(contact)
       
   482     QVariant variant = property.variantValue();
       
   483     if (property.valueType() != QVersitProperty::ListType
       
   484             || variant.type() != QVariant::StringList)
       
   485         return false;
       
   486     QStringList values = variant.toStringList();
       
   487     QStringList contexts = extractContexts(property);
       
   488     foreach(const QString& value, values) {
       
   489         if (!value.isEmpty()) {
       
   490             QContactNickname nickName;
       
   491             nickName.setNickname(value);
       
   492             saveDetailWithContext(updatedDetails, nickName, contexts);
       
   493         }
       
   494     }
       
   495     return true;
       
   496 }
       
   497 
       
   498 /*!
       
   499  * Creates QContactTags from \a property
       
   500  */
       
   501 bool QVersitContactImporterPrivate::createTags(
       
   502     const QVersitProperty& property,
       
   503     QContact* contact,
       
   504     QList<QContactDetail>* updatedDetails)
       
   505 {
       
   506     Q_UNUSED(contact)
       
   507     QVariant variant = property.variantValue();
       
   508     if (property.valueType() != QVersitProperty::ListType
       
   509             || variant.type() != QVariant::StringList)
       
   510         return false;
       
   511     QStringList values = variant.toStringList();
       
   512     QStringList contexts = extractContexts(property);
       
   513     foreach(const QString& value, values) {
       
   514         if (!value.isEmpty()) {
       
   515             QContactTag tag;
       
   516             tag.setTag(value);
       
   517             saveDetailWithContext(updatedDetails, tag, contexts);
       
   518         }
       
   519     }
       
   520     return true;
       
   521 }
       
   522 
       
   523 /*!
       
   524  * Creates a QContactOnlineAccount from \a property
       
   525  */
       
   526 bool QVersitContactImporterPrivate::createOnlineAccount(
       
   527     const QVersitProperty& property,
       
   528     QContact* contact,
       
   529     QList<QContactDetail>* updatedDetails)
       
   530 {
       
   531     Q_UNUSED(contact)
       
   532     QContactOnlineAccount onlineAccount;
       
   533     QString value(property.value());
       
   534     if (value.isEmpty())
       
   535         return false;
       
   536     onlineAccount.setAccountUri(property.value());
       
   537     if (property.name() == QLatin1String("X-SIP")) {
       
   538         QStringList subTypes = extractSubTypes(property);
       
   539         if (subTypes.isEmpty())
       
   540             subTypes.append(QContactOnlineAccount::SubTypeSip);
       
   541         onlineAccount.setSubTypes(subTypes);
       
   542     } else if (property.name() == QLatin1String("X-IMPP") ||
       
   543                property.name() == QLatin1String("IMPP") ||
       
   544                property.name() == QLatin1String("X-JABBER")) {
       
   545         onlineAccount.setSubTypes(QContactOnlineAccount::SubTypeImpp);
       
   546     }
       
   547 
       
   548     saveDetailWithContext(updatedDetails, onlineAccount, extractContexts(property));
       
   549     return true;
       
   550 }
       
   551 
       
   552 /*!
       
   553  * Creates a QContactRingtone from \a property
       
   554  */
       
   555 bool QVersitContactImporterPrivate::createRingtone(
       
   556     const QVersitProperty& property,
       
   557     QContact* contact,
       
   558     QList<QContactDetail>* updatedDetails)
       
   559 {
       
   560     Q_UNUSED(contact)
       
   561     QString location;
       
   562     QByteArray data;
       
   563     if (saveDataFromProperty(property, &location, &data) && !location.isEmpty()) {
       
   564         QContactRingtone ringtone;
       
   565         ringtone.setAudioRingtoneUrl(location);
       
   566         saveDetailWithContext(updatedDetails, ringtone, extractContexts(property));
       
   567         return true;
       
   568     }
       
   569     return false;
       
   570 }
       
   571 
       
   572 /*!
       
   573  * Creates a QContactAvatar from \a property
       
   574  */
       
   575 bool QVersitContactImporterPrivate::createThumbnail(
       
   576     const QVersitProperty& property,
       
   577     QContact* contact,
       
   578     QList<QContactDetail>* updatedDetails)
       
   579 {
       
   580     QString location;
       
   581     QByteArray data;
       
   582     bool success = false;
       
   583 
       
   584     if (saveDataFromProperty(property, &location, &data) && !location.isEmpty()) {
       
   585         QContactAvatar avatar;
       
   586         avatar.setImageUrl(location);
       
   587         saveDetailWithContext(updatedDetails, avatar, extractContexts(property));
       
   588         success = true;
       
   589     }
       
   590     if (!data.isEmpty()) {
       
   591         QImage image;
       
   592         if (image.loadFromData(data)) {
       
   593             QContactThumbnail thumbnail = contact->detail<QContactThumbnail>();
       
   594             // In the case of multiple thumbnails, pick the smallest one.
       
   595             if (thumbnail.isEmpty() || image.byteCount() < thumbnail.thumbnail().byteCount()) {
       
   596                 thumbnail.setThumbnail(image);
       
   597             }
       
   598             saveDetailWithContext(updatedDetails, thumbnail, extractContexts(property));
       
   599             success = true;
       
   600         }
       
   601     }
       
   602 
       
   603     return success;
       
   604 }
       
   605 
       
   606 /*!
       
   607  * Creates a QContactGeoLocation from \a property
       
   608  */
       
   609 bool QVersitContactImporterPrivate::createGeoLocation(
       
   610     const QVersitProperty& property,
       
   611     QContact* contact,
       
   612     QList<QContactDetail>* updatedDetails)
       
   613 {
       
   614     Q_UNUSED(contact)
       
   615     QContactGeoLocation geo;
       
   616     QVariant variant = property.variantValue();
       
   617     if (property.valueType() != QVersitProperty::CompoundType
       
   618             || variant.type() != QVariant::StringList)
       
   619         return false;
       
   620     QStringList values = variant.toStringList();
       
   621     bool ok1;
       
   622     geo.setLongitude(takeFirst(values).toDouble(&ok1));
       
   623     bool ok2;
       
   624     geo.setLatitude(takeFirst(values).toDouble(&ok2));
       
   625 
       
   626     if (ok1 && ok2) {
       
   627         saveDetailWithContext(updatedDetails, geo, extractContexts(property));
       
   628         return true;
       
   629     } else {
       
   630         return false;
       
   631     }
       
   632 }
       
   633 
       
   634 /*!
       
   635  * Creates a QContactFamily from \a property
       
   636  */
       
   637 bool QVersitContactImporterPrivate::createFamily(
       
   638     const QVersitProperty& property,
       
   639     QContact* contact,
       
   640     QList<QContactDetail>* updatedDetails)
       
   641 {
       
   642     QString val = property.value();
       
   643     QContactFamily family = contact->detail<QContactFamily>();
       
   644     if (property.name() == QLatin1String("X-SPOUSE")) {
       
   645         if (val.isEmpty())
       
   646             return false;
       
   647         family.setSpouse(val);
       
   648     } else if (property.name() == QLatin1String("X-CHILDREN")) {
       
   649         QVariant variant = property.variantValue();
       
   650         if (property.valueType() != QVersitProperty::ListType
       
   651                 || variant.type() != QVariant::StringList)
       
   652             return false;
       
   653         QStringList values = variant.toStringList();
       
   654         if (values.isEmpty())
       
   655             return false;
       
   656         family.setChildren(values);
       
   657     } else {
       
   658         return false;
       
   659     }
       
   660 
       
   661     saveDetailWithContext(updatedDetails, family, extractContexts(property));
       
   662     return true;
       
   663 }
       
   664 
       
   665 /*!
       
   666  * Creates a simple name-value contact detail.
       
   667  */
       
   668 bool QVersitContactImporterPrivate::createNameValueDetail(
       
   669     const QVersitProperty& property,
       
   670     QContact* contact,
       
   671     QList<QContactDetail>* updatedDetails)
       
   672 {
       
   673     Q_UNUSED(contact)
       
   674     QString value(property.value());
       
   675     if (value.isEmpty())
       
   676         return false;
       
   677     QPair<QString,QString> nameAndValueType =
       
   678         mDetailMappings.value(property.name());
       
   679     if (nameAndValueType.first.isEmpty())
       
   680         return false;
       
   681 
       
   682     QContactDetail detail(nameAndValueType.first);
       
   683     detail.setValue(nameAndValueType.second, value);
       
   684 
       
   685     saveDetailWithContext(updatedDetails, detail, extractContexts(property));
       
   686     return true;
       
   687 }
       
   688 
       
   689 /*!
       
   690  * Find an existing QContactName and set the CustomLabel field on it
       
   691  */
       
   692 bool QVersitContactImporterPrivate::createCustomLabel(
       
   693     const QVersitProperty& property,
       
   694     QContact* contact,
       
   695     QList<QContactDetail>* updatedDetails)
       
   696 {
       
   697     QString label(property.value());
       
   698     if (!label.isEmpty()) {
       
   699         QContactName name;
       
   700         QContactName existingName = contact->detail<QContactName>();
       
   701         if (!existingName.isEmpty()) {
       
   702             name = existingName;
       
   703         }
       
   704 
       
   705         name.setCustomLabel(property.value());
       
   706 
       
   707         saveDetailWithContext(updatedDetails, name, extractContexts(property));
       
   708         return true;
       
   709     } else {
       
   710         return false;
       
   711     }
       
   712 }
       
   713 
       
   714 /*!
       
   715  * Extracts the list of contexts from \a types
       
   716  */
       
   717 QStringList QVersitContactImporterPrivate::extractContexts(
       
   718     const QVersitProperty& property) const
       
   719 {
       
   720     QStringList types = property.parameters().values(QLatin1String("TYPE"));
       
   721     QStringList contexts;
       
   722     foreach (const QString& type, types) {
       
   723         QString value = mContextMappings.value(type.toUpper());
       
   724         if (value.length() > 0)
       
   725             contexts.append(value);
       
   726     }
       
   727     return contexts;
       
   728 }
       
   729 
       
   730 /*!
       
   731  * Extracts the list of subtypes from \a property
       
   732  */
       
   733 QStringList QVersitContactImporterPrivate::extractSubTypes(
       
   734     const QVersitProperty& property) const
       
   735 {
       
   736     QStringList types = property.parameters().values(QLatin1String("TYPE"));
       
   737     QStringList subTypes;
       
   738     foreach (const QString& type, types) {
       
   739         QString subType = mSubTypeMappings.value(type.toUpper());
       
   740         if (subType.length() > 0)
       
   741             subTypes += subType;
       
   742     }
       
   743     return subTypes;
       
   744 }
       
   745 
       
   746 /*!
       
   747  * Takes the first value in \a list, or an empty QString is if the list is empty.
       
   748  */
       
   749 QString QVersitContactImporterPrivate::takeFirst(QList<QString>& list) const
       
   750 {
       
   751     return list.empty() ? QString() : list.takeFirst();
       
   752 }
       
   753 
       
   754 /*!
       
   755  * Parses a date and time from text
       
   756  */
       
   757 QDateTime QVersitContactImporterPrivate::parseDateTime(
       
   758     const QString& value,
       
   759     const QString& format) const
       
   760 {
       
   761     QDateTime dateTime;
       
   762     if (value.contains(QLatin1Char('-'))) {
       
   763         dateTime = QDateTime::fromString(value,Qt::ISODate);
       
   764     } else {
       
   765         dateTime = QDateTime::fromString(value, format);
       
   766     }
       
   767     return dateTime;
       
   768 }
       
   769 
       
   770 /*!
       
   771  * Extracts either a location (URI/filepath) from a \a property, or data (eg. if it was base64
       
   772  * encoded).  If the property contains data, an attempt is made to save it and the location of the
       
   773  * saved resource is recovered to *\a location.  The data is stored into *\a data.
       
   774  */
       
   775 bool QVersitContactImporterPrivate::saveDataFromProperty(const QVersitProperty &property,
       
   776                                                             QString *location,
       
   777                                                             QByteArray *data) const
       
   778 {
       
   779     bool found = false;
       
   780     const QString valueParam = property.parameters().value(QLatin1String("VALUE"));
       
   781     QVariant variant(property.variantValue());
       
   782     if (variant.type() == QVariant::String
       
   783         || valueParam == QLatin1String("URL")) {
       
   784         *location = property.value();
       
   785         found |= !location->isEmpty();
       
   786     } else if (variant.type() == QVariant::ByteArray) {
       
   787         *data = variant.toByteArray();
       
   788         if (!data->isEmpty()) {
       
   789             found = true;
       
   790             *location = saveContentToFile(property, *data);
       
   791         }
       
   792     }
       
   793     return found;
       
   794 }
       
   795 
       
   796 /*!
       
   797  * Writes \a data to a file and returns the filename.  \a property specifies the context in which
       
   798  * the data was found.
       
   799  */
       
   800 QString QVersitContactImporterPrivate::saveContentToFile(
       
   801     const QVersitProperty& property, const QByteArray& data) const
       
   802 {
       
   803     QString filename;
       
   804     bool ok = false;
       
   805     if (mResourceHandler)
       
   806         ok = mResourceHandler->saveResource(data, property, &filename);
       
   807     return ok ? filename : QString();
       
   808 }
       
   809 
       
   810 /*!
       
   811  * Adds \a detail to the \a updatedDetails list.  Also sets the contexts to \a contexts if it is not
       
   812  * empty.
       
   813  */
       
   814 void QVersitContactImporterPrivate::saveDetailWithContext(
       
   815         QList<QContactDetail>* updatedDetails,
       
   816         QContactDetail detail,
       
   817         const QStringList& contexts)
       
   818 {
       
   819     if (!contexts.isEmpty())
       
   820         detail.setContexts(contexts);
       
   821     updatedDetails->append(detail);
       
   822 }
       
   823 
       
   824 /*! Synthesize the display label from the name of the contact, or, failing that, the nickname of
       
   825 the contact, or failing that, the organisation of the contact.
       
   826 Returns the synthesized display label.
       
   827  */
       
   828 QString QVersitContactImporterPrivate::synthesizedDisplayLabel(const QContact& contact)
       
   829 {
       
   830     /* XXX This is copied and modified from QContactManagerEngine.  This should be made a public
       
   831        static function in QCME and called here */
       
   832     QList<QContactName> allNames = contact.details<QContactName>();
       
   833 
       
   834     const QLatin1String space(" ");
       
   835 
       
   836     // synthesize the display label from the name.
       
   837     foreach (const QContactName& name, allNames) {
       
   838         if (!name.customLabel().isEmpty()) {
       
   839             // default behaviour is to allow the user to define a custom display label.
       
   840             return name.customLabel();
       
   841         }
       
   842 
       
   843         QString result;
       
   844         if (!name.value(QContactName::FieldPrefix).trimmed().isEmpty()) {
       
   845            result += name.value(QContactName::FieldPrefix);
       
   846         }
       
   847         if (!name.value(QContactName::FieldFirstName).trimmed().isEmpty()) {
       
   848             if (!result.isEmpty())
       
   849                 result += space;
       
   850             result += name.value(QContactName::FieldFirstName);
       
   851         }
       
   852         if (!name.value(QContactName::FieldMiddleName).trimmed().isEmpty()) {
       
   853             if (!result.isEmpty())
       
   854                 result += space;
       
   855             result += name.value(QContactName::FieldMiddleName);
       
   856         }
       
   857         if (!name.value(QContactName::FieldLastName).trimmed().isEmpty()) {
       
   858             if (!result.isEmpty())
       
   859                 result += space;
       
   860             result += name.value(QContactName::FieldLastName);
       
   861         }
       
   862         if (!name.value(QContactName::FieldSuffix).trimmed().isEmpty()) {
       
   863             if (!result.isEmpty())
       
   864                 result += space;
       
   865             result += name.value(QContactName::FieldSuffix);
       
   866         }
       
   867         if (!result.isEmpty())
       
   868             return result;
       
   869     }
       
   870 
       
   871     QList<QContactNickname> allNicknames = contact.details<QContactNickname>();
       
   872     foreach (const QContactNickname& nickname, allNicknames) {
       
   873         if (!nickname.nickname().isEmpty())
       
   874             return nickname.nickname();
       
   875     }
       
   876 
       
   877     /* Well, we had no non empty names. if we have orgs, fall back to those */
       
   878     QList<QContactOrganization> allOrgs = contact.details<QContactOrganization>();
       
   879     foreach (const QContactOrganization& org, allOrgs) {
       
   880         if (!org.name().isEmpty())
       
   881             return org.name();
       
   882     }
       
   883 
       
   884     return QString();
       
   885 }