diff --git a/src/field.cpp b/src/field.cpp index cba3d393..f727ba6b 100644 --- a/src/field.cpp +++ b/src/field.cpp @@ -1,658 +1,656 @@ /* This file is part of the KContacts framework. Copyright (c) 2002 Cornelius Schumacher This library is free software; you can redistribute it and/or modify it under the terms of the GNU Library General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public License for more details. You should have received a copy of the GNU Library General Public License along with this library; see the file COPYING.LIB. If not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #include #include #include #include #include "field.h" using namespace KContacts; class Q_DECL_HIDDEN Field::Private { public: Private(int fieldId, int category = 0, const QString &label = QString(), const QString &key = QString(), const QString &app = QString()) : mFieldId(fieldId) , mCategory(category) , mLabel(label) , mKey(key) , mApp(app) { } enum FieldId { CustomField, FormattedName, FamilyName, GivenName, AdditionalName, Prefix, Suffix, NickName, Birthday, HomeAddressStreet, HomeAddressPostOfficeBox, HomeAddressLocality, HomeAddressRegion, HomeAddressPostalCode, HomeAddressCountry, HomeAddressLabel, BusinessAddressStreet, BusinessAddressPostOfficeBox, BusinessAddressLocality, BusinessAddressRegion, BusinessAddressPostalCode, BusinessAddressCountry, BusinessAddressLabel, HomePhone, BusinessPhone, MobilePhone, HomeFax, BusinessFax, CarPhone, Isdn, Pager, Email, Mailer, Title, Role, Organization, Department, Note, Url }; int fieldId() const { return mFieldId; } int category() const { return mCategory; } QString label() const { return mLabel; } QString key() const { return mKey; } QString app() const { return mApp; } static Field::List mAllFields; static Field::List mDefaultFields; static Field::List mCustomFields; private: int mFieldId; int mCategory; QString mLabel; QString mKey; QString mApp; }; Field::List Field::Private::mAllFields; Field::List Field::Private::mDefaultFields; Field::List Field::Private::mCustomFields; Field::Field(Private *p) : d(p) { } Field::~Field() { delete d; } QString Field::label() { switch (d->fieldId()) { case Private::FormattedName: return Addressee::formattedNameLabel(); case Private::FamilyName: return Addressee::familyNameLabel(); case Private::GivenName: return Addressee::givenNameLabel(); case Private::AdditionalName: return Addressee::additionalNameLabel(); case Private::Prefix: return Addressee::prefixLabel(); case Private::Suffix: return Addressee::suffixLabel(); case Private::NickName: return Addressee::nickNameLabel(); case Private::Birthday: return Addressee::birthdayLabel(); case Private::HomeAddressStreet: return Addressee::homeAddressStreetLabel(); case Private::HomeAddressPostOfficeBox: return Addressee::homeAddressPostOfficeBoxLabel(); case Private::HomeAddressLocality: return Addressee::homeAddressLocalityLabel(); case Private::HomeAddressRegion: return Addressee::homeAddressRegionLabel(); case Private::HomeAddressPostalCode: return Addressee::homeAddressPostalCodeLabel(); case Private::HomeAddressCountry: return Addressee::homeAddressCountryLabel(); case Private::HomeAddressLabel: return Addressee::homeAddressLabelLabel(); case Private::BusinessAddressStreet: return Addressee::businessAddressStreetLabel(); case Private::BusinessAddressPostOfficeBox: return Addressee::businessAddressPostOfficeBoxLabel(); case Private::BusinessAddressLocality: return Addressee::businessAddressLocalityLabel(); case Private::BusinessAddressRegion: return Addressee::businessAddressRegionLabel(); case Private::BusinessAddressPostalCode: return Addressee::businessAddressPostalCodeLabel(); case Private::BusinessAddressCountry: return Addressee::businessAddressCountryLabel(); case Private::BusinessAddressLabel: return Addressee::businessAddressLabelLabel(); case Private::HomePhone: return Addressee::homePhoneLabel(); case Private::BusinessPhone: return Addressee::businessPhoneLabel(); case Private::MobilePhone: return Addressee::mobilePhoneLabel(); case Private::HomeFax: return Addressee::homeFaxLabel(); case Private::BusinessFax: return Addressee::businessFaxLabel(); case Private::CarPhone: return Addressee::carPhoneLabel(); case Private::Isdn: return Addressee::isdnLabel(); case Private::Pager: return Addressee::pagerLabel(); case Private::Email: return Addressee::emailLabel(); case Private::Mailer: return Addressee::mailerLabel(); case Private::Title: return Addressee::titleLabel(); case Private::Role: return Addressee::roleLabel(); case Private::Organization: return Addressee::organizationLabel(); case Private::Department: return Addressee::departmentLabel(); case Private::Note: return Addressee::noteLabel(); case Private::Url: return Addressee::urlLabel(); case Private::CustomField: return d->label(); default: return i18n("Unknown Field"); } } int Field::category() { return d->category(); } QString Field::categoryLabel(int category) { switch (category) { case All: return i18n("All"); case Frequent: return i18n("Frequent"); case Address: return i18nc("street/postal", "Address"); case Email: return i18n("Email"); case Personal: return i18n("Personal"); case Organization: return i18n("Organization"); case CustomCategory: return i18n("Custom"); default: return i18n("Undefined"); } } QString Field::value(const KContacts::Addressee &a) { switch (d->fieldId()) { case Private::FormattedName: return a.formattedName(); case Private::FamilyName: return a.familyName(); case Private::GivenName: return a.givenName(); case Private::AdditionalName: return a.additionalName(); case Private::Prefix: return a.prefix(); case Private::Suffix: return a.suffix(); case Private::NickName: return a.nickName(); case Private::Mailer: return a.mailer(); case Private::Title: return a.title(); case Private::Role: return a.role(); case Private::Organization: return a.organization(); case Private::Department: return a.department(); case Private::Note: return a.note(); case Private::Email: return a.preferredEmail(); case Private::Birthday: if (a.birthday().isValid()) { return a.birthday().date().toString(Qt::ISODate); } else { return QString(); } case Private::Url: return a.url().url().toDisplayString(); case Private::HomePhone: { PhoneNumber::List::ConstIterator it; { // check for preferred number const PhoneNumber::List list = a.phoneNumbers(PhoneNumber::Home | PhoneNumber::Pref); PhoneNumber::List::ConstIterator end(list.end()); for (it = list.begin(); it != end; ++it) { if (((*it).type() & ~(PhoneNumber::Pref)) == PhoneNumber::Home) { return (*it).number(); } } } { // check for normal home number const PhoneNumber::List list = a.phoneNumbers(PhoneNumber::Home); PhoneNumber::List::ConstIterator end(list.end()); for (it = list.begin(); it != end; ++it) { if (((*it).type() & ~(PhoneNumber::Pref)) == PhoneNumber::Home) { return (*it).number(); } } } return QString(); } case Private::BusinessPhone: { PhoneNumber::List::ConstIterator it; { // check for preferred number const PhoneNumber::List list = a.phoneNumbers(PhoneNumber::Work | PhoneNumber::Pref); PhoneNumber::List::ConstIterator end(list.end()); for (it = list.begin(); it != end; ++it) { if (((*it).type() & ~(PhoneNumber::Pref)) == PhoneNumber::Work) { return (*it).number(); } } } { // check for normal work number const PhoneNumber::List list = a.phoneNumbers(PhoneNumber::Work); for (it = list.begin(); it != list.end(); ++it) { if (((*it).type() & ~(PhoneNumber::Pref)) == PhoneNumber::Work) { return (*it).number(); } } } return QString(); } case Private::MobilePhone: return a.phoneNumber(PhoneNumber::Cell).number(); case Private::HomeFax: return a.phoneNumber(PhoneNumber::Home | PhoneNumber::Fax).number(); case Private::BusinessFax: return a.phoneNumber(PhoneNumber::Work | PhoneNumber::Fax).number(); case Private::CarPhone: return a.phoneNumber(PhoneNumber::Car).number(); case Private::Isdn: return a.phoneNumber(PhoneNumber::Isdn).number(); case Private::Pager: return a.phoneNumber(PhoneNumber::Pager).number(); case Private::HomeAddressStreet: return a.address(Address::Home).street(); case Private::HomeAddressPostOfficeBox: return a.address(Address::Home).postOfficeBox(); case Private::HomeAddressLocality: return a.address(Address::Home).locality(); case Private::HomeAddressRegion: return a.address(Address::Home).region(); case Private::HomeAddressPostalCode: return a.address(Address::Home).postalCode(); case Private::HomeAddressCountry: return a.address(Address::Home).country(); case Private::BusinessAddressStreet: return a.address(Address::Work).street(); case Private::BusinessAddressPostOfficeBox: return a.address(Address::Work).postOfficeBox(); case Private::BusinessAddressLocality: return a.address(Address::Work).locality(); case Private::BusinessAddressRegion: return a.address(Address::Work).region(); case Private::BusinessAddressPostalCode: return a.address(Address::Work).postalCode(); case Private::BusinessAddressCountry: return a.address(Address::Work).country(); case Private::CustomField: return a.custom(d->app(), d->key()); default: return QString(); } } bool Field::setValue(KContacts::Addressee &a, const QString &value) { switch (d->fieldId()) { case Private::FormattedName: a.setFormattedName(value); return true; case Private::FamilyName: a.setFamilyName(value); return true; case Private::GivenName: a.setGivenName(value); return true; case Private::AdditionalName: a.setAdditionalName(value); return true; case Private::Prefix: a.setPrefix(value); return true; case Private::Suffix: a.setSuffix(value); return true; case Private::NickName: a.setNickName(value); return true; case Private::Mailer: a.setMailer(value); return true; case Private::Title: a.setTitle(value); return true; case Private::Role: a.setRole(value); return true; case Private::Organization: a.setOrganization(value); return true; case Private::Department: a.setDepartment(value); return true; case Private::Note: a.setNote(value); return true; case Private::Birthday: a.setBirthday(QDate::fromString(value, Qt::ISODate)); return true; case Private::CustomField: a.insertCustom(d->app(), d->key(), value); return true; default: return false; } } QString Field::sortKey(const KContacts::Addressee &a) { switch (d->fieldId()) { case Private::FormattedName: return a.formattedName(); case Private::FamilyName: return a.familyName(); case Private::GivenName: return a.givenName(); case Private::AdditionalName: return a.additionalName(); case Private::Prefix: return a.prefix(); case Private::Suffix: return a.suffix(); case Private::NickName: return a.nickName(); case Private::Mailer: return a.mailer(); case Private::Title: return a.title(); case Private::Role: return a.role(); case Private::Organization: return a.organization(); case Private::Department: return a.department(); case Private::Note: return a.note(); case Private::Birthday: if (a.birthday().isValid()) { QDate date = a.birthday().date(); - QString key; - key.sprintf("%02d-%02d", date.month(), date.day()); - return key; + return QString::asprintf("%02d-%02d", date.month(), date.day()); } else { return QStringLiteral("00-00"); } default: return value(a).toLower(); } } bool Field::isCustom() { return d->fieldId() == Private::CustomField; } Field::List Field::allFields() { if (Private::mAllFields.isEmpty()) { createField(Private::FormattedName, Frequent); createField(Private::FamilyName, Frequent); createField(Private::GivenName, Frequent); createField(Private::AdditionalName); createField(Private::Prefix); createField(Private::Suffix); createField(Private::NickName, Personal); createField(Private::Birthday, Personal); createField(Private::HomeAddressStreet, Address | Personal); createField(Private::HomeAddressPostOfficeBox, Address | Personal); createField(Private::HomeAddressLocality, Address | Personal); createField(Private::HomeAddressRegion, Address | Personal); createField(Private::HomeAddressPostalCode, Address | Personal); createField(Private::HomeAddressCountry, Address | Personal); createField(Private::HomeAddressLabel, Address | Personal); createField(Private::BusinessAddressStreet, Address | Organization); createField(Private::BusinessAddressPostOfficeBox, Address | Organization); createField(Private::BusinessAddressLocality, Address | Organization); createField(Private::BusinessAddressRegion, Address | Organization); createField(Private::BusinessAddressPostalCode, Address | Organization); createField(Private::BusinessAddressCountry, Address | Organization); createField(Private::BusinessAddressLabel, Address | Organization); createField(Private::HomePhone, Personal | Frequent); createField(Private::BusinessPhone, Organization | Frequent); createField(Private::MobilePhone, Frequent); createField(Private::HomeFax); createField(Private::BusinessFax); createField(Private::CarPhone); createField(Private::Isdn); createField(Private::Pager); createField(Private::Email, Email | Frequent); createField(Private::Mailer, Email); createField(Private::Title, Organization); createField(Private::Role, Organization); createField(Private::Organization, Organization); createField(Private::Department, Organization); createField(Private::Note); createField(Private::Url); } return Private::mAllFields; } Field::List Field::defaultFields() { if (Private::mDefaultFields.isEmpty()) { createDefaultField(Private::FormattedName); createDefaultField(Private::Email); } return Private::mDefaultFields; } void Field::createField(int id, int category) { Private::mAllFields.append(new Field(new Private(id, category))); } void Field::createDefaultField(int id, int category) { Private::mDefaultFields.append(new Field(new Private(id, category))); } void Field::deleteFields() { Field::List::ConstIterator it; for (it = Private::mAllFields.constBegin(); it != Private::mAllFields.constEnd(); ++it) { delete(*it); } Private::mAllFields.clear(); for (it = Private::mDefaultFields.constBegin(); it != Private::mDefaultFields.constEnd(); ++it) { delete(*it); } Private::mDefaultFields.clear(); for (it = Private::mCustomFields.constBegin(); it != Private::mCustomFields.constEnd(); ++it) { delete(*it); } Private::mCustomFields.clear(); } void Field::saveFields(const QString &identifier, const Field::List &fields) { KConfigGroup cg(KSharedConfig::openConfig(), "KABCFields"); saveFields(cg, identifier, fields); } void Field::saveFields(KConfigGroup &cfg, const QString &identifier, const Field::List &fields) { QList fieldIds; int custom = 0; Field::List::ConstIterator it; fieldIds.reserve(fields.count()); for (it = fields.begin(); it != fields.end(); ++it) { fieldIds.append((*it)->d->fieldId()); if ((*it)->isCustom()) { QStringList customEntry; customEntry << (*it)->d->label(); customEntry << (*it)->d->key(); customEntry << (*it)->d->app(); cfg.writeEntry(QLatin1String("KCONTACTS_CustomEntry_") + identifier + QLatin1Char('_') +QString::number(custom++), customEntry); } } cfg.writeEntry(identifier, fieldIds); } Field::List Field::restoreFields(const QString &identifier) { KConfigGroup cg(KSharedConfig::openConfig(), "KABCFields"); return restoreFields(cg, identifier); } Field::List Field::restoreFields(const KConfigGroup &cfg, const QString &identifier) { const QList fieldIds = cfg.readEntry(identifier, QList()); Field::List fields; int custom = 0; QList::ConstIterator it; fields.reserve(fieldIds.count()); for (it = fieldIds.begin(); it != fieldIds.end(); ++it) { Private *f = nullptr; if ((*it) == Private::CustomField) { QStringList customEntry = cfg.readEntry(QLatin1String("KCONTACTS_CustomEntry_") +identifier + QLatin1Char('_') +QString::number(custom++), QStringList()); f = new Private(*it, CustomCategory, customEntry[ 0 ], customEntry[ 1 ], customEntry[ 2 ]); } else { f = new Private(*it); } fields.append(new Field(f)); } return fields; } bool Field::equals(Field *field) { bool sameId = (d->fieldId() == field->d->fieldId()); if (!sameId) { return false; } if (d->fieldId() != Private::CustomField) { return true; } return d->key() == field->d->key(); } Field *Field::createCustomField(const QString &label, int category, const QString &key, const QString &app) { Field *field = new Field(new Private(Private::CustomField, category | CustomCategory, label, key, app)); Private::mCustomFields.append(field); return field; } diff --git a/src/vcardtool.cpp b/src/vcardtool.cpp index 77a1cbfb..b35a130e 100644 --- a/src/vcardtool.cpp +++ b/src/vcardtool.cpp @@ -1,1596 +1,1594 @@ /* This file is part of the KContacts framework. Copyright (c) 2003 Tobias Koenig Copyright (C) 2015-2019 Laurent Montel This library is free software; you can redistribute it and/or modify it under the terms of the GNU Library General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public License for more details. You should have received a copy of the GNU Library General Public License along with this library; see the file COPYING.LIB. If not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #include "vcardtool_p.h" #include "key.h" #include "picture.h" #include "secrecy.h" #include "sound.h" #include "lang.h" #include "gender.h" #include "related.h" #include "fieldgroup.h" #include "kcontacts_debug.h" #include #include #include #include using namespace KContacts; static bool needsEncoding(const QString &value) { int length = value.length(); for (int i = 0; i < length; ++i) { char c = value.at(i).toLatin1(); if ((c < 33 || c > 126) && c != ' ' && c != '=') { return true; } } return false; } static const struct { const char *addressType; Address::TypeFlag flag; } s_addressTypes[] = { { "dom", Address::Dom }, { "home", Address::Home }, { "intl", Address::Intl }, { "parcel", Address::Parcel }, { "postal", Address::Postal }, { "pref", Address::Pref }, { "work", Address::Work }, }; static const unsigned int s_numAddressTypes = sizeof s_addressTypes / sizeof *s_addressTypes; static Address::TypeFlag stringToAddressType(const QString &str) { for (unsigned int i = 0; i < s_numAddressTypes; ++i) { if (str == QLatin1String(s_addressTypes[i].addressType)) { return s_addressTypes[i].flag; } } return {}; } static const struct { const char *phoneType; PhoneNumber::TypeFlag flag; } s_phoneTypes[] = { { "BBS", PhoneNumber::Bbs }, { "CAR", PhoneNumber::Car }, { "CELL", PhoneNumber::Cell }, { "FAX", PhoneNumber::Fax }, { "HOME", PhoneNumber::Home }, { "ISDN", PhoneNumber::Isdn }, { "MODEM", PhoneNumber::Modem }, { "MSG", PhoneNumber::Msg }, { "PAGER", PhoneNumber::Pager }, { "PCS", PhoneNumber::Pcs }, { "PREF", PhoneNumber::Pref }, { "VIDEO", PhoneNumber::Video }, { "VOICE", PhoneNumber::Voice }, { "WORK", PhoneNumber::Work }, }; static const unsigned int s_numPhoneTypes = sizeof s_phoneTypes / sizeof *s_phoneTypes; static PhoneNumber::TypeFlag stringToPhoneType(const QString &str) { for (unsigned int i = 0; i < s_numPhoneTypes; ++i) { if (str == QLatin1String(s_phoneTypes[i].phoneType)) { return s_phoneTypes[i].flag; } } return {}; } VCardTool::VCardTool() { } VCardTool::~VCardTool() { } QByteArray VCardTool::exportVCards(const Addressee::List &list, VCard::Version version) const { return createVCards(list, version, true /*export vcard*/); } QByteArray VCardTool::createVCards(const Addressee::List &list, VCard::Version version) const { return createVCards(list, version, false /*don't export*/); } void VCardTool::addParameters(VCardLine &line, const QMap ¶ms) const { QMapIterator i(params); while (i.hasNext()) { i.next(); line.addParameter(i.key(), i.value().join(QLatin1Char(','))); } } void VCardTool::addParameter(VCardLine &line, VCard::Version version, const QString &key, const QStringList &valueStringList) const { if (version == VCard::v2_1) { for (const QString &valueStr : valueStringList) { line.addParameter(valueStr, QString()); } } else if (version == VCard::v3_0) { line.addParameter(key, valueStringList.join(QLatin1Char(','))); } else { if (valueStringList.count() < 2) { line.addParameter(key, valueStringList.join(QLatin1Char(','))); } else { line.addParameter(key, QLatin1Char('"') + valueStringList.join(QLatin1Char(',')) + QLatin1Char('"')); } } } QByteArray VCardTool::createVCards(const Addressee::List &list, VCard::Version version, bool exportVcard) const { VCard::List vCardList; Addressee::List::ConstIterator addrIt; Addressee::List::ConstIterator listEnd(list.constEnd()); for (addrIt = list.constBegin(); addrIt != listEnd; ++addrIt) { VCard card; QStringList::ConstIterator strIt; // VERSION if (version == VCard::v2_1) { card.addLine(VCardLine(QStringLiteral("VERSION"), QStringLiteral("2.1"))); } else if (version == VCard::v3_0) { card.addLine(VCardLine(QStringLiteral("VERSION"), QStringLiteral("3.0"))); } else if (version == VCard::v4_0) { card.addLine(VCardLine(QStringLiteral("VERSION"), QStringLiteral("4.0"))); } // ADR + LABEL const Address::List addresses = (*addrIt).addresses(); Address::List::ConstIterator end(addresses.end()); for (Address::List::ConstIterator it = addresses.begin(); it != end; ++it) { QStringList address; const bool isEmpty = ((*it).postOfficeBox().isEmpty() && (*it).extended().isEmpty() && (*it).street().isEmpty() && (*it).locality().isEmpty() && (*it).region().isEmpty() && (*it).postalCode().isEmpty() && (*it).country().isEmpty()); address.append((*it).postOfficeBox().replace(QLatin1Char(';'), QStringLiteral("\\;"))); address.append((*it).extended().replace(QLatin1Char(';'), QStringLiteral("\\;"))); address.append((*it).street().replace(QLatin1Char(';'), QStringLiteral("\\;"))); address.append((*it).locality().replace(QLatin1Char(';'), QStringLiteral("\\;"))); address.append((*it).region().replace(QLatin1Char(';'), QStringLiteral("\\;"))); address.append((*it).postalCode().replace(QLatin1Char(';'), QStringLiteral("\\;"))); address.append((*it).country().replace(QLatin1Char(';'), QStringLiteral("\\;"))); const QString addressJoined(address.join(QLatin1Char(';'))); VCardLine adrLine(QStringLiteral("ADR"), addressJoined); if (version == VCard::v2_1 && needsEncoding(addressJoined)) { adrLine.addParameter(QStringLiteral("charset"), QStringLiteral("UTF-8")); adrLine.addParameter(QStringLiteral("encoding"), QStringLiteral("QUOTED-PRINTABLE")); } const bool hasLabel = !(*it).label().isEmpty(); QStringList addreLineType; QStringList labelLineType; for (unsigned int i = 0; i < s_numAddressTypes; ++i) { if (s_addressTypes[i].flag & (*it).type()) { const QString str = QString::fromLatin1(s_addressTypes[i].addressType); addreLineType << str; if (hasLabel) { labelLineType << str; } } } if (hasLabel) { if (version == VCard::v4_0) { if (!(*it).label().isEmpty()) { adrLine.addParameter(QStringLiteral("LABEL"), QStringLiteral("\"%1\"").arg((*it).label())); } } else { VCardLine labelLine(QStringLiteral("LABEL"), (*it).label()); if (version == VCard::v2_1 && needsEncoding((*it).label())) { labelLine.addParameter(QStringLiteral("charset"), QStringLiteral("UTF-8")); labelLine.addParameter(QStringLiteral("encoding"), QStringLiteral("QUOTED-PRINTABLE")); } addParameter(labelLine, version, QStringLiteral("TYPE"), labelLineType); card.addLine(labelLine); } } if (version == VCard::v4_0) { Geo geo = (*it).geo(); if (geo.isValid()) { - QString str; - str.sprintf("\"geo:%.6f,%.6f\"", geo.latitude(), geo.longitude()); + QString str = QString::asprintf("\"geo:%.6f,%.6f\"", geo.latitude(), geo.longitude()); adrLine.addParameter(QStringLiteral("GEO"), str); } } if (!isEmpty) { addParameter(adrLine, version, QStringLiteral("TYPE"), addreLineType); card.addLine(adrLine); } } // BDAY const bool withTime = (*addrIt).birthdayHasTime(); const QString birthdayString = createDateTime((*addrIt).birthday(), version, withTime); card.addLine(VCardLine(QStringLiteral("BDAY"), birthdayString)); //Laurent: 31 Jan 2015. Not necessary to export it. When Categories were changes as AkonadiTag nobody thought that it was break categorie support... //=> not necessary to export just tag... // CATEGORIES only > 2.1 if (!exportVcard) { if (version != VCard::v2_1) { QStringList categories = (*addrIt).categories(); QStringList::Iterator catIt; QStringList::Iterator catEnd(categories.end()); for (catIt = categories.begin(); catIt != catEnd; ++catIt) { (*catIt).replace(QLatin1Char(','), QStringLiteral("\\,")); } VCardLine catLine(QStringLiteral("CATEGORIES"), categories.join(QLatin1Char(','))); card.addLine(catLine); } } // MEMBER (only in 4.0) if (version == VCard::v4_0) { // The KIND property must be set to "group" in order to use this property. if ((*addrIt).kind().toLower() == QLatin1String("group")) { const QStringList lst = (*addrIt).members(); for (const QString &member : lst) { VCardLine line(QStringLiteral("MEMBER"), member); card.addLine(line); } } } // SOURCE const QVector lstUrl = (*addrIt).sourcesUrlList(); for (const QUrl &url : lstUrl) { VCardLine line = VCardLine(QStringLiteral("SOURCE"), url.url()); card.addLine(line); } const Related::List relatedList = (*addrIt).relationships(); Related::List::ConstIterator relatedIt; Related::List::ConstIterator relatedEnd(relatedList.end()); for (relatedIt = relatedList.begin(); relatedIt != relatedEnd; ++relatedIt) { VCardLine line(QStringLiteral("RELATED"), (*relatedIt).related()); addParameters(line, (*relatedIt).parameters()); card.addLine(line); } // CLASS only for version == 3.0 if (version == VCard::v3_0) { card.addLine(createSecrecy((*addrIt).secrecy())); } // LANG only for version == 4.0 if (version == VCard::v4_0) { const Lang::List langList = (*addrIt).langs(); Lang::List::ConstIterator langIt; Lang::List::ConstIterator langEnd(langList.end()); for (langIt = langList.begin(); langIt != langEnd; ++langIt) { VCardLine line(QStringLiteral("LANG"), (*langIt).language()); addParameters(line, (*langIt).parameters()); card.addLine(line); } } // CLIENTPIDMAP if (version == VCard::v4_0) { const ClientPidMap::List clientpidmapList = (*addrIt).clientPidMapList(); ClientPidMap::List::ConstIterator clientPidMapIt; ClientPidMap::List::ConstIterator clientPidMapEnd(clientpidmapList.end()); for (clientPidMapIt = clientpidmapList.begin(); clientPidMapIt != clientPidMapEnd; ++clientPidMapIt) { VCardLine line(QStringLiteral("CLIENTPIDMAP"), (*clientPidMapIt).clientPidMap()); addParameters(line, (*clientPidMapIt).parameters()); card.addLine(line); } } // EMAIL const Email::List emailList = (*addrIt).emailList(); Email::List::ConstIterator emailIt; Email::List::ConstIterator emailEnd(emailList.end()); for (emailIt = emailList.begin(); emailIt != emailEnd; ++emailIt) { VCardLine line(QStringLiteral("EMAIL"), (*emailIt).mail()); QMapIterator i((*emailIt).parameters()); while (i.hasNext()) { i.next(); if (version == VCard::v2_1) { if (i.key().toLower() == QLatin1String("type")) { QStringList valueStringList = i.value(); bool hasPreferred = false; const int removeItems = valueStringList.removeAll(QStringLiteral("PREF")); if (removeItems > 0) { hasPreferred = true; } if (!valueStringList.isEmpty()) { addParameter(line, version, i.key(), valueStringList); } if (hasPreferred) { line.addParameter(QStringLiteral("PREF"), QString()); } } else { line.addParameter(i.key(), i.value().join(QLatin1Char(','))); } } else { line.addParameter(i.key(), i.value().join(QLatin1Char(','))); } } card.addLine(line); } // FN required for only version > 2.1 VCardLine fnLine(QStringLiteral("FN"), (*addrIt).formattedName()); if (version == VCard::v2_1 && needsEncoding((*addrIt).formattedName())) { fnLine.addParameter(QStringLiteral("charset"), QStringLiteral("UTF-8")); fnLine.addParameter(QStringLiteral("encoding"), QStringLiteral("QUOTED-PRINTABLE")); } card.addLine(fnLine); // GEO const Geo geo = (*addrIt).geo(); if (geo.isValid()) { QString str; if (version == VCard::v4_0) { - str.sprintf("geo:%.6f,%.6f", geo.latitude(), geo.longitude()); + str = QString::asprintf("geo:%.6f,%.6f", geo.latitude(), geo.longitude()); } else { - str.sprintf("%.6f;%.6f", geo.latitude(), geo.longitude()); + str = QString::asprintf("%.6f;%.6f", geo.latitude(), geo.longitude()); } card.addLine(VCardLine(QStringLiteral("GEO"), str)); } // KEY const Key::List keys = (*addrIt).keys(); Key::List::ConstIterator keyIt; Key::List::ConstIterator keyEnd(keys.end()); for (keyIt = keys.begin(); keyIt != keyEnd; ++keyIt) { card.addLine(createKey(*keyIt, version)); } // LOGO card.addLine(createPicture(QStringLiteral("LOGO"), (*addrIt).logo(), version)); const QVector lstLogo = (*addrIt).extraLogoList(); for (const Picture &logo : lstLogo) { card.addLine(createPicture(QStringLiteral("LOGO"), logo, version)); } // MAILER only for version < 4.0 if (version != VCard::v4_0) { VCardLine mailerLine(QStringLiteral("MAILER"), (*addrIt).mailer()); if (version == VCard::v2_1 && needsEncoding((*addrIt).mailer())) { mailerLine.addParameter(QStringLiteral("charset"), QStringLiteral("UTF-8")); mailerLine.addParameter(QStringLiteral("encoding"), QStringLiteral("QUOTED-PRINTABLE")); } card.addLine(mailerLine); } // N required for only version < 4.0 QStringList name; name.append((*addrIt).familyName().replace(QLatin1Char(';'), QStringLiteral("\\;"))); name.append((*addrIt).givenName().replace(QLatin1Char(';'), QStringLiteral("\\;"))); name.append((*addrIt).additionalName().replace(QLatin1Char(';'), QStringLiteral("\\;"))); name.append((*addrIt).prefix().replace(QLatin1Char(';'), QStringLiteral("\\;"))); name.append((*addrIt).suffix().replace(QLatin1Char(';'), QStringLiteral("\\;"))); VCardLine nLine(QStringLiteral("N"), name.join(QLatin1Char(';'))); if (version == VCard::v2_1 && needsEncoding(name.join(QLatin1Char(';')))) { nLine.addParameter(QStringLiteral("charset"), QStringLiteral("UTF-8")); nLine.addParameter(QStringLiteral("encoding"), QStringLiteral("QUOTED-PRINTABLE")); } if (version == VCard::v4_0 && !(*addrIt).sortString().isEmpty()) { nLine.addParameter(QStringLiteral("SORT-AS"), (*addrIt).sortString()); } card.addLine(nLine); // NAME only for version < 4.0 if (version != VCard::v4_0) { VCardLine nameLine(QStringLiteral("NAME"), (*addrIt).name()); if (version == VCard::v2_1 && needsEncoding((*addrIt).name())) { nameLine.addParameter(QStringLiteral("charset"), QStringLiteral("UTF-8")); nameLine.addParameter(QStringLiteral("encoding"), QStringLiteral("QUOTED-PRINTABLE")); } card.addLine(nameLine); } // NICKNAME only for version > 2.1 if (version != VCard::v2_1) { const QVector lstNickName = (*addrIt).extraNickNameList(); for (const NickName &nickName : lstNickName) { VCardLine nickNameLine(QStringLiteral("NICKNAME"), nickName.nickname()); addParameters(nickNameLine, nickName.parameters()); card.addLine(nickNameLine); } } // NOTE VCardLine noteLine(QStringLiteral("NOTE"), (*addrIt).note()); if (version == VCard::v2_1 && needsEncoding((*addrIt).note())) { noteLine.addParameter(QStringLiteral("charset"), QStringLiteral("UTF-8")); noteLine.addParameter(QStringLiteral("encoding"), QStringLiteral("QUOTED-PRINTABLE")); } card.addLine(noteLine); // ORG const QVector lstOrg = (*addrIt).extraOrganizationList(); for (const Org &org : lstOrg) { QStringList organization; organization.append(org.organization().replace(QLatin1Char(';'), QStringLiteral("\\;"))); if (!(*addrIt).department().isEmpty()) { organization.append((*addrIt).department().replace(QLatin1Char(';'), QStringLiteral("\\;"))); } const QString orgStr = organization.join(QLatin1Char(';')); VCardLine orgLine(QStringLiteral("ORG"), orgStr); if (version == VCard::v2_1 && needsEncoding(orgStr)) { orgLine.addParameter(QStringLiteral("charset"), QStringLiteral("UTF-8")); orgLine.addParameter(QStringLiteral("encoding"), QStringLiteral("QUOTED-PRINTABLE")); } addParameters(orgLine, org.parameters()); card.addLine(orgLine); } // PHOTO card.addLine(createPicture(QStringLiteral("PHOTO"), (*addrIt).photo(), version)); const QVector lstExtraPhoto = (*addrIt).extraPhotoList(); for (const Picture &photo : lstExtraPhoto) { card.addLine(createPicture(QStringLiteral("PHOTO"), photo, version)); } // PROID only for version > 2.1 if (version != VCard::v2_1) { card.addLine(VCardLine(QStringLiteral("PRODID"), (*addrIt).productId())); } // REV card.addLine(VCardLine(QStringLiteral("REV"), createDateTime((*addrIt).revision(), version))); // ROLE const QVector lstExtraRole = (*addrIt).extraRoleList(); for (const Role &role : lstExtraRole) { VCardLine roleLine(QStringLiteral("ROLE"), role.role()); if (version == VCard::v2_1 && needsEncoding(role.role())) { roleLine.addParameter(QStringLiteral("charset"), QStringLiteral("UTF-8")); roleLine.addParameter(QStringLiteral("encoding"), QStringLiteral("QUOTED-PRINTABLE")); } addParameters(roleLine, role.parameters()); card.addLine(roleLine); } // SORT-STRING if (version == VCard::v3_0) { card.addLine(VCardLine(QStringLiteral("SORT-STRING"), (*addrIt).sortString())); } // SOUND card.addLine(createSound((*addrIt).sound(), version)); const QVector lstSound = (*addrIt).extraSoundList(); for (const Sound &sound : lstSound) { card.addLine(createSound(sound, version)); } // TEL const PhoneNumber::List phoneNumbers = (*addrIt).phoneNumbers(); PhoneNumber::List::ConstIterator phoneIt; PhoneNumber::List::ConstIterator phoneEnd(phoneNumbers.end()); for (phoneIt = phoneNumbers.begin(); phoneIt != phoneEnd; ++phoneIt) { VCardLine line(QStringLiteral("TEL"), (*phoneIt).number()); QMapIterator i((*phoneIt).parameters()); while (i.hasNext()) { i.next(); if (i.key().toUpper() != QLatin1String("TYPE")) { line.addParameter(i.key(), i.value().join(QLatin1Char(','))); } } QStringList lst; for (unsigned int i = 0; i < s_numPhoneTypes; ++i) { if (s_phoneTypes[i].flag & (*phoneIt).type()) { const QString str = QString::fromLatin1(s_phoneTypes[i].phoneType); if (version == VCard::v4_0) { lst << str.toLower(); } else { lst << str; } } } if (!lst.isEmpty()) { addParameter(line, version, QStringLiteral("TYPE"), lst); } card.addLine(line); } // TITLE const QVector lstTitle = (*addrIt).extraTitleList(); for (const Title &title : lstTitle) { VCardLine titleLine(QStringLiteral("TITLE"), title.title()); if (version == VCard::v2_1 && needsEncoding(title.title())) { titleLine.addParameter(QStringLiteral("charset"), QStringLiteral("UTF-8")); titleLine.addParameter(QStringLiteral("encoding"), QStringLiteral("QUOTED-PRINTABLE")); } addParameters(titleLine, title.parameters()); card.addLine(titleLine); } // TZ // TODO Add vcard4.0 support const TimeZone timeZone = (*addrIt).timeZone(); if (timeZone.isValid()) { - QString str; int neg = 1; if (timeZone.offset() < 0) { neg = -1; } - str.sprintf("%c%02d:%02d", (timeZone.offset() >= 0 ? '+' : '-'), + QString str = QString::asprintf("%c%02d:%02d", (timeZone.offset() >= 0 ? '+' : '-'), (timeZone.offset() / 60) * neg, (timeZone.offset() % 60) * neg); card.addLine(VCardLine(QStringLiteral("TZ"), str)); } // UID card.addLine(VCardLine(QStringLiteral("UID"), (*addrIt).uid())); // URL const QVector<ResourceLocatorUrl> lstExtraUrl = (*addrIt).extraUrlList(); for (const ResourceLocatorUrl &url : lstExtraUrl) { VCardLine line(QStringLiteral("URL"), url.url()); addParameters(line, url.parameters()); card.addLine(line); } if (version == VCard::v4_0) { // GENDER const Gender gender = (*addrIt).gender(); if (gender.isValid()) { QString genderStr; if (!gender.gender().isEmpty()) { genderStr = gender.gender(); } if (!gender.comment().isEmpty()) { genderStr += QLatin1Char(';') + gender.comment(); } VCardLine line(QStringLiteral("GENDER"), genderStr); card.addLine(line); } // KIND if (!(*addrIt).kind().isEmpty()) { VCardLine line(QStringLiteral("KIND"), (*addrIt).kind()); card.addLine(line); } } // From vcard4. if (version == VCard::v4_0) { const QVector<CalendarUrl> lstCalendarUrl = (*addrIt).calendarUrlList(); for (const CalendarUrl &url : lstCalendarUrl) { if (url.isValid()) { QString type; switch (url.type()) { case CalendarUrl::Unknown: case CalendarUrl::EndCalendarType: break; case CalendarUrl::FBUrl: type = QStringLiteral("FBURL"); break; case CalendarUrl::CALUri: type = QStringLiteral("CALURI"); break; case CalendarUrl::CALADRUri: type = QStringLiteral("CALADRURI"); break; } if (!type.isEmpty()) { VCardLine line(type, url.url().toDisplayString()); addParameters(line, url.parameters()); card.addLine(line); } } } } //FieldGroup const QVector<FieldGroup> lstGroup = (*addrIt).fieldGroupList(); for (const FieldGroup &group : lstGroup) { VCardLine line(group.fieldGroupName(), group.value()); addParameters(line, group.parameters()); card.addLine(line); } // IMPP (supported in vcard 3 too) const QVector<Impp> lstImpp = (*addrIt).imppList(); for (const Impp &impp : lstImpp) { VCardLine line(QStringLiteral("IMPP"), impp.address().url()); QMapIterator<QString, QStringList> i(impp.parameters()); while (i.hasNext()) { i.next(); if (i.key().toLower() != QStringLiteral("x-service-type")) { line.addParameter(i.key(), i.value().join(QLatin1Char(','))); } } card.addLine(line); } // X- const QStringList customs = (*addrIt).customs(); for (strIt = customs.begin(); strIt != customs.end(); ++strIt) { QString identifier = QLatin1String("X-") +(*strIt).left((*strIt).indexOf(QLatin1Char(':'))); const QString value = (*strIt).mid((*strIt).indexOf(QLatin1Char(':')) + 1); if (value.isEmpty()) { continue; } //Convert to standard identifier if (exportVcard) { if (identifier == QLatin1String("X-messaging/aim-All")) { identifier = QStringLiteral("X-AIM"); } else if (identifier == QLatin1String("X-messaging/icq-All")) { identifier = QStringLiteral("X-ICQ"); } else if (identifier == QLatin1String("X-messaging/xmpp-All")) { identifier = QStringLiteral("X-JABBER"); } else if (identifier == QLatin1String("X-messaging/msn-All")) { identifier = QStringLiteral("X-MSN"); } else if (identifier == QLatin1String("X-messaging/yahoo-All")) { identifier = QStringLiteral("X-YAHOO"); } else if (identifier == QLatin1String("X-messaging/gadu-All")) { identifier = QStringLiteral("X-GADUGADU"); } else if (identifier == QLatin1String("X-messaging/skype-All")) { identifier = QStringLiteral("X-SKYPE"); } else if (identifier == QLatin1String("X-messaging/groupwise-All")) { identifier = QStringLiteral("X-GROUPWISE"); } else if (identifier == QLatin1String("X-messaging/sms-All")) { identifier = QStringLiteral("X-SMS"); } else if (identifier == QLatin1String("X-messaging/meanwhile-All")) { identifier = QStringLiteral("X-MEANWHILE"); } else if (identifier == QLatin1String("X-messaging/irc-All")) { identifier = QStringLiteral("X-IRC"); //Not defined by rfc but need for fixing #300869 } else if (identifier == QLatin1String("X-messaging/googletalk-All")) { //Not defined by rfc but need for fixing #300869 identifier = QStringLiteral("X-GTALK"); } else if (identifier == QLatin1String("X-messaging/twitter-All")) { identifier = QStringLiteral("X-TWITTER"); } } if (identifier.toLower() == QLatin1String("x-kaddressbook-x-anniversary") && version == VCard::v4_0) { // ANNIVERSARY if (!value.isEmpty()) { const QDate date = QDate::fromString(value, Qt::ISODate); QDateTime dt = QDateTime(date); dt.setTime(QTime()); VCardLine line(QStringLiteral("ANNIVERSARY"), createDateTime(dt, version, false)); card.addLine(line); } } else if (identifier.toLower() == QLatin1String("x-kaddressbook-x-spousesname") && version == VCard::v4_0) { if (!value.isEmpty()) { VCardLine line(QStringLiteral("RELATED"), QStringLiteral(";")); line.addParameter(QStringLiteral("TYPE"), QStringLiteral("spouse")); line.addParameter(QStringLiteral("VALUE"), value); card.addLine(line); } } else { VCardLine line(identifier, value); if (version == VCard::v2_1 && needsEncoding(value)) { line.addParameter(QStringLiteral("charset"), QStringLiteral("UTF-8")); line.addParameter(QStringLiteral("encoding"), QStringLiteral("QUOTED-PRINTABLE")); } card.addLine(line); } } vCardList.append(card); } return VCardParser::createVCards(vCardList); } Addressee::List VCardTool::parseVCards(const QByteArray &vcard) const { static const QLatin1Char semicolonSep(';'); static const QLatin1Char commaSep(','); QString identifier; QString group; Addressee::List addrList; const VCard::List vCardList = VCardParser::parseVCards(vcard); VCard::List::ConstIterator cardIt; VCard::List::ConstIterator listEnd(vCardList.end()); for (cardIt = vCardList.begin(); cardIt != listEnd; ++cardIt) { Addressee addr; const QStringList idents = (*cardIt).identifiers(); QStringList::ConstIterator identIt; QStringList::ConstIterator identEnd(idents.end()); for (identIt = idents.begin(); identIt != identEnd; ++identIt) { const VCardLine::List lines = (*cardIt).lines((*identIt)); VCardLine::List::ConstIterator lineIt; // iterate over the lines for (lineIt = lines.begin(); lineIt != lines.end(); ++lineIt) { identifier = (*lineIt).identifier().toLower(); group = (*lineIt).group(); if (!group.isEmpty()) { KContacts::FieldGroup groupField(group + QLatin1Char('.') + (*lineIt).identifier()); groupField.setParameters((*lineIt).parameterMap()); groupField.setValue((*lineIt).value().toString()); addr.insertFieldGroup(groupField); } // ADR else if (identifier == QLatin1String("adr")) { Address address; const QStringList addrParts = splitString(semicolonSep, (*lineIt).value().toString()); const int addrPartsCount(addrParts.count()); if (addrPartsCount > 0) { address.setPostOfficeBox(addrParts.at(0)); } if (addrPartsCount > 1) { address.setExtended(addrParts.at(1)); } if (addrPartsCount > 2) { address.setStreet(addrParts.at(2)); } if (addrPartsCount > 3) { address.setLocality(addrParts.at(3)); } if (addrPartsCount > 4) { address.setRegion(addrParts.at(4)); } if (addrPartsCount > 5) { address.setPostalCode(addrParts.at(5)); } if (addrPartsCount > 6) { address.setCountry(addrParts.at(6)); } Address::Type type; const QStringList types = (*lineIt).parameters(QStringLiteral("type")); QStringList::ConstIterator end(types.end()); for (QStringList::ConstIterator it = types.begin(); it != end; ++it) { type |= stringToAddressType((*it).toLower()); } address.setType(type); QString label = (*lineIt).parameter(QStringLiteral("label")); if (!label.isEmpty()) { if (label.length() > 1) { if (label.at(0) == QLatin1Char('"') && label.at(label.length() - 1) == QLatin1Char('"')) { label = label.mid(1, label.length() - 2); } } address.setLabel(label); } QString geoStr = (*lineIt).parameter(QStringLiteral("geo")); if (!geoStr.isEmpty()) { geoStr.remove(QLatin1Char('\"')); geoStr.remove(QStringLiteral("geo:")); if (geoStr.contains(QLatin1Char(','))) { QStringList arguments = geoStr.split(QLatin1Char(',')); KContacts::Geo geo; geo.setLatitude(arguments.at(0).toDouble()); geo.setLongitude(arguments.at(1).toDouble()); address.setGeo(geo); } } addr.insertAddress(address); } // ANNIVERSARY else if (identifier == QLatin1String("anniversary")) { const QString t = (*lineIt).value().toString(); const QDateTime dt(parseDateTime(t)); addr.insertCustom(QStringLiteral("KADDRESSBOOK"), QStringLiteral("X-Anniversary"), dt.date().toString(Qt::ISODate)); } // BDAY else if (identifier == QLatin1String("bday")) { bool withTime; const QDateTime bday = parseDateTime((*lineIt).value().toString(), &withTime); addr.setBirthday(bday, withTime); } // CATEGORIES else if (identifier == QLatin1String("categories")) { const QStringList categories = splitString(commaSep, (*lineIt).value().toString()); addr.setCategories(categories); } // FBURL else if (identifier == QLatin1String("fburl")) { CalendarUrl calurl; calurl.setType(CalendarUrl::FBUrl); const QUrl url = QUrl((*lineIt).value().toString()); calurl.setUrl(url); calurl.setParameters((*lineIt).parameterMap()); addr.insertCalendarUrl(calurl); } // CALADRURI else if (identifier == QLatin1String("caladruri")) { CalendarUrl calurl; calurl.setType(CalendarUrl::CALADRUri); const QUrl url = QUrl((*lineIt).value().toString()); calurl.setUrl(url); calurl.setParameters((*lineIt).parameterMap()); addr.insertCalendarUrl(calurl); } // CALURI else if (identifier == QLatin1String("caluri")) { CalendarUrl calurl; calurl.setType(CalendarUrl::CALUri); const QUrl url = QUrl((*lineIt).value().toString()); calurl.setUrl(url); calurl.setParameters((*lineIt).parameterMap()); addr.insertCalendarUrl(calurl); } //IMPP else if (identifier == QLatin1String("impp")) { QUrl imppUrl((*lineIt).value().toString()); Impp impp; impp.setParameters((*lineIt).parameterMap()); if (!(*lineIt).parameter(QStringLiteral("x-service-type")).isEmpty() && imppUrl.scheme().isEmpty()) { imppUrl.setScheme(normalizeImppServiceType((*lineIt).parameter(QStringLiteral("x-service-type")).toLower())); } impp.setAddress(imppUrl); addr.insertImpp(impp); } // CLASS else if (identifier == QLatin1String("class")) { addr.setSecrecy(parseSecrecy(*lineIt)); } // GENDER else if (identifier == QLatin1String("gender")) { QString genderStr = (*lineIt).value().toString(); if (!genderStr.isEmpty()) { Gender gender; if (genderStr.at(0) != QLatin1Char(';')) { gender.setGender(genderStr.at(0)); if (genderStr.length() > 2 && (genderStr.at(1) == QLatin1Char(';'))) { gender.setComment(genderStr.right(genderStr.length() - 2)); } } else { gender.setComment(genderStr.right(genderStr.length() - 1)); } addr.setGender(gender); } } // LANG else if (identifier == QLatin1String("lang")) { Lang lang; lang.setLanguage((*lineIt).value().toString()); lang.setParameters((*lineIt).parameterMap()); addr.insertLang(lang); } // EMAIL else if (identifier == QLatin1String("email")) { const QStringList types = (*lineIt).parameters(QStringLiteral("type")); addr.insertEmail((*lineIt).value().toString(), types.contains(QLatin1String("PREF")), (*lineIt).parameterMap()); } // KIND else if (identifier == QLatin1String("kind")) { addr.setKind((*lineIt).value().toString()); } // FN else if (identifier == QLatin1String("fn")) { addr.setFormattedName((*lineIt).value().toString()); } // GEO else if (identifier == QLatin1String("geo")) { Geo geo; QString lineStr = (*lineIt).value().toString(); if (lineStr.startsWith(QLatin1String("geo:"))) { //VCard 4.0 lineStr.remove(QStringLiteral("geo:")); const QStringList geoParts = lineStr.split(QLatin1Char(','), QString::KeepEmptyParts); if (geoParts.size() >= 2) { geo.setLatitude(geoParts.at(0).toFloat()); geo.setLongitude(geoParts.at(1).toFloat()); addr.setGeo(geo); } } else { const QStringList geoParts = lineStr.split(QLatin1Char(';'), QString::KeepEmptyParts); if (geoParts.size() >= 2) { geo.setLatitude(geoParts.at(0).toFloat()); geo.setLongitude(geoParts.at(1).toFloat()); addr.setGeo(geo); } } } // KEY else if (identifier == QLatin1String("key")) { addr.insertKey(parseKey(*lineIt)); } // LABEL else if (identifier == QLatin1String("label")) { Address::Type type; const QStringList types = (*lineIt).parameters(QStringLiteral("type")); QStringList::ConstIterator end(types.end()); for (QStringList::ConstIterator it = types.begin(); it != end; ++it) { type |= stringToAddressType((*it).toLower()); } bool available = false; KContacts::Address::List addressList = addr.addresses(); for (KContacts::Address::List::Iterator it = addressList.begin(); it != addressList.end(); ++it) { if ((*it).type() == type) { (*it).setLabel((*lineIt).value().toString()); addr.insertAddress(*it); available = true; break; } } if (!available) { // a standalone LABEL tag KContacts::Address address(type); address.setLabel((*lineIt).value().toString()); addr.insertAddress(address); } } // LOGO else if (identifier == QLatin1String("logo")) { Picture picture = parsePicture(*lineIt); if (addr.logo().isEmpty()) { addr.setLogo(picture); } else { addr.insertExtraLogo(picture); } } // MAILER else if (identifier == QLatin1String("mailer")) { addr.setMailer((*lineIt).value().toString()); } // N else if (identifier == QLatin1String("n")) { const QStringList nameParts = splitString(semicolonSep, (*lineIt).value().toString()); const int numberOfParts(nameParts.count()); if (numberOfParts > 0) { addr.setFamilyName(nameParts.at(0)); } if (numberOfParts > 1) { addr.setGivenName(nameParts.at(1)); } if (numberOfParts > 2) { addr.setAdditionalName(nameParts.at(2)); } if (numberOfParts > 3) { addr.setPrefix(nameParts.at(3)); } if (numberOfParts > 4) { addr.setSuffix(nameParts.at(4)); } if (!(*lineIt).parameter(QStringLiteral("sort-as")).isEmpty()) { addr.setSortString((*lineIt).parameter(QStringLiteral("sort-as"))); } } // NAME else if (identifier == QLatin1String("name")) { addr.setName((*lineIt).value().toString()); } // NICKNAME else if (identifier == QLatin1String("nickname")) { NickName nickName((*lineIt).value().toString()); nickName.setParameters((*lineIt).parameterMap()); addr.insertExtraNickName(nickName); } // NOTE else if (identifier == QLatin1String("note")) { addr.setNote((*lineIt).value().toString()); } // ORGANIZATION else if (identifier == QLatin1String("org")) { const QStringList orgParts = splitString(semicolonSep, (*lineIt).value().toString()); const int orgPartsCount(orgParts.count()); if (orgPartsCount > 0) { Org organization(orgParts.at(0)); organization.setParameters((*lineIt).parameterMap()); addr.insertExtraOrganization(organization); } if (orgPartsCount > 1) { addr.setDepartment(orgParts.at(1)); } if (!(*lineIt).parameter(QStringLiteral("sort-as")).isEmpty()) { addr.setSortString((*lineIt).parameter(QStringLiteral("sort-as"))); } } // PHOTO else if (identifier == QLatin1String("photo")) { Picture picture = parsePicture(*lineIt); if (addr.photo().isEmpty()) { addr.setPhoto(picture); } else { addr.insertExtraPhoto(picture); } } // PROID else if (identifier == QLatin1String("prodid")) { addr.setProductId((*lineIt).value().toString()); } // REV else if (identifier == QLatin1String("rev")) { addr.setRevision(parseDateTime((*lineIt).value().toString())); } // ROLE else if (identifier == QLatin1String("role")) { Role role((*lineIt).value().toString()); role.setParameters((*lineIt).parameterMap()); addr.insertExtraRole(role); } // SORT-STRING else if (identifier == QLatin1String("sort-string")) { addr.setSortString((*lineIt).value().toString()); } // SOUND else if (identifier == QLatin1String("sound")) { Sound sound = parseSound(*lineIt); if (addr.sound().isEmpty()) { addr.setSound(sound); } else { addr.insertExtraSound(sound); } } // TEL else if (identifier == QLatin1String("tel")) { PhoneNumber phone; phone.setNumber((*lineIt).value().toString()); PhoneNumber::Type type; bool foundType = false; const QStringList types = (*lineIt).parameters(QStringLiteral("type")); QStringList::ConstIterator typeEnd(types.constEnd()); for (QStringList::ConstIterator it = types.constBegin(); it != typeEnd; ++it) { type |= stringToPhoneType((*it).toUpper()); foundType = true; } phone.setType(foundType ? type : PhoneNumber::Undefined); phone.setParameters((*lineIt).parameterMap()); addr.insertPhoneNumber(phone); } // TITLE else if (identifier == QLatin1String("title")) { Title title((*lineIt).value().toString()); title.setParameters((*lineIt).parameterMap()); addr.insertExtraTitle(title); } // TZ else if (identifier == QLatin1String("tz")) { //TODO add vcard4 support TimeZone tz; const QString date = (*lineIt).value().toString(); if (!date.isEmpty()) { int hours = date.midRef(1, 2).toInt(); int minutes = date.midRef(4, 2).toInt(); int offset = (hours * 60) + minutes; offset = offset * (date[ 0 ] == QLatin1Char('+') ? 1 : -1); tz.setOffset(offset); addr.setTimeZone(tz); } } // UID else if (identifier == QLatin1String("uid")) { addr.setUid((*lineIt).value().toString()); } // URL else if (identifier == QLatin1String("url")) { const QUrl url = QUrl((*lineIt).value().toString()); ResourceLocatorUrl resourceLocatorUrl; resourceLocatorUrl.setUrl(url); resourceLocatorUrl.setParameters((*lineIt).parameterMap()); addr.insertExtraUrl(resourceLocatorUrl); } // SOURCE else if (identifier == QLatin1String("source")) { const QUrl url = QUrl((*lineIt).value().toString()); addr.insertSourceUrl(url); } // MEMBER (vcard 4.0) else if (identifier == QLatin1String("member")) { addr.insertMember((*lineIt).value().toString()); } // RELATED (vcard 4.0) else if (identifier == QLatin1String("related")) { Related related; related.setRelated((*lineIt).value().toString()); related.setParameters((*lineIt).parameterMap()); addr.insertRelationship(related); } // CLIENTPIDMAP (vcard 4.0) else if (identifier == QLatin1String("clientpidmap")) { ClientPidMap clientpidmap; clientpidmap.setClientPidMap((*lineIt).value().toString()); clientpidmap.setParameters((*lineIt).parameterMap()); addr.insertClientPidMap(clientpidmap); } // X- //TODO import X-GENDER else if (identifier.startsWith(QLatin1String("x-"))) { QString ident = (*lineIt).identifier(); //X-Evolution // also normalize case of our own extensions, some backends "adjust" that if (identifier == QLatin1String("x-evolution-spouse") || identifier == QLatin1String("x-spouse")) { ident = QStringLiteral("X-KADDRESSBOOK-X-SpousesName"); } else if (identifier == QLatin1String("x-evolution-blog-url") || identifier.compare(QLatin1String("X-KADDRESSBOOK-BLOGFEED"), Qt::CaseInsensitive) == 0) { ident = QStringLiteral("X-KADDRESSBOOK-BlogFeed"); } else if (identifier == QLatin1String("x-evolution-assistant") || identifier == QLatin1String("x-assistant") || identifier.compare(QLatin1String("X-KADDRESSBOOK-X-ASSISTANTSNAME"), Qt::CaseInsensitive) == 0) { ident = QStringLiteral("X-KADDRESSBOOK-X-AssistantsName"); } else if (identifier == QLatin1String("x-evolution-anniversary") || identifier == QLatin1String("x-anniversary") || identifier.compare(QLatin1String("X-KADDRESSBOOK-X-ANNIVERSARY"), Qt::CaseInsensitive) == 0) { ident = QStringLiteral("X-KADDRESSBOOK-X-Anniversary"); } else if (identifier == QLatin1String("x-evolution-manager") || identifier == QLatin1String("x-manager") || identifier.compare(QLatin1String("X-KADDRESSBOOK-X-MANAGERSNAME"), Qt::CaseInsensitive) == 0) { ident = QStringLiteral("X-KADDRESSBOOK-X-ManagersName"); } else if (identifier.compare(QLatin1String("X-KADDRESSBOOK-X-PROFESSION"), Qt::CaseInsensitive) == 0) { ident = QStringLiteral("X-KADDRESSBOOK-X-Profession"); } else if (identifier.compare(QLatin1String("X-KADDRESSBOOK-X-OFFICE"), Qt::CaseInsensitive) == 0) { ident = QStringLiteral("X-KADDRESSBOOK-X-Office"); } else if (identifier.compare(QLatin1String("X-KADDRESSBOOK-X-SPOUSESNAME"), Qt::CaseInsensitive) == 0) { ident = QStringLiteral("X-KADDRESSBOOK-X-SpousesName"); } else if (identifier == QLatin1String("x-aim")) { ident = QStringLiteral("X-messaging/aim-All"); } else if (identifier == QLatin1String("x-icq")) { ident = QStringLiteral("X-messaging/icq-All"); } else if (identifier == QLatin1String("x-jabber")) { ident = QStringLiteral("X-messaging/xmpp-All"); } else if (identifier == QLatin1String("x-jabber")) { ident = QStringLiteral("X-messaging/xmpp-All"); } else if (identifier == QLatin1String("x-msn")) { ident = QStringLiteral("X-messaging/msn-All"); } else if (identifier == QLatin1String("x-yahoo")) { ident = QStringLiteral("X-messaging/yahoo-All"); } else if (identifier == QLatin1String("x-gadugadu")) { ident = QStringLiteral("X-messaging/gadu-All"); } else if (identifier == QLatin1String("x-skype")) { ident = QStringLiteral("X-messaging/skype-All"); } else if (identifier == QLatin1String("x-groupwise")) { ident = QStringLiteral("X-messaging/groupwise-All"); } else if (identifier == QLatin1String("x-sms")) { ident = QStringLiteral("X-messaging/sms-All"); } else if (identifier == QLatin1String("x-meanwhile")) { ident = QStringLiteral("X-messaging/meanwhile-All"); } else if (identifier == QLatin1String("x-irc")) { ident = QStringLiteral("X-messaging/irc-All"); } else if (identifier == QLatin1String("x-gtalk")) { ident = QStringLiteral("X-messaging/googletalk-All"); } else if (identifier == QLatin1String("x-twitter")) { ident = QStringLiteral("X-messaging/twitter-All"); } const QString key = ident.mid(2); const int dash = key.indexOf(QLatin1Char('-')); addr.insertCustom(key.left(dash), key.mid(dash + 1), (*lineIt).value().toString()); } } } addrList.append(addr); } return addrList; } QDateTime VCardTool::parseDateTime(const QString &str, bool *timeValid) { const int posT = str.indexOf(QLatin1Char('T')); QString dateString = posT >= 0 ? str.left(posT) : str; const bool noYear = dateString.startsWith(QLatin1String("--")); dateString = dateString.remove(QLatin1Char('-')); QDate date; if (noYear) { date = QDate::fromString(dateString, QStringLiteral("MMdd")); date = date.addYears(-1900); } else { date = QDate::fromString(dateString, QStringLiteral("yyyyMMdd")); } QTime time; Qt::TimeSpec spec = Qt::LocalTime; int offsetSecs = 0; if (posT >= 0) { QString timeString = str.mid(posT + 1); timeString = timeString.remove(QLatin1Char(':')); const int zPos = timeString.indexOf(QLatin1Char('Z')); const int plusPos = timeString.indexOf(QLatin1Char('+')); const int minusPos = timeString.indexOf(QLatin1Char('-')); const int tzPos = qMax(qMax(zPos, plusPos), minusPos); const QString hhmmssString = tzPos >= 0 ? timeString.left(tzPos) : timeString; switch (hhmmssString.size()) { case 2: time = QTime::fromString(hhmmssString, QStringLiteral("hh")); break; case 4: time = QTime::fromString(hhmmssString, QStringLiteral("hhmm")); break; case 6: time = QTime::fromString(hhmmssString, QStringLiteral("hhmmss")); break; } if (tzPos >= 0) { if (zPos >= 0) { spec = Qt::UTC; } else { spec = Qt::OffsetFromUTC; QTime offsetTime; const QString offsetString = timeString.mid(tzPos + 1); switch (offsetString.size()) { case 2: offsetTime = QTime::fromString(offsetString, QStringLiteral("hh")); break; case 4: offsetTime = QTime::fromString(offsetString, QStringLiteral("hhmm")); break; } offsetSecs = offsetTime.hour() * 3600 + offsetTime.minute() * 60; } if (minusPos >= 0) { offsetSecs *= -1; } } } if (timeValid) { *timeValid = time.isValid(); } return QDateTime(date, time, spec, offsetSecs); } QString VCardTool::createDateTime(const QDateTime &dateTime, VCard::Version version, bool withTime) { if (!dateTime.date().isValid()) { return QString(); } QString str = createDate(dateTime.date(), version); if (!withTime) { return str; } str += createTime(dateTime.time(), version); if (dateTime.timeSpec() == Qt::UTC) { str += QLatin1Char('Z'); } else if (dateTime.timeSpec() == Qt::OffsetFromUTC) { const int offsetSecs = dateTime.offsetFromUtc(); if (offsetSecs >= 0) { str += QLatin1Char('+'); } else { str += QLatin1Char('-'); } QTime offsetTime = QTime(0, 0).addSecs(abs(offsetSecs)); if (version == VCard::v4_0) { str += offsetTime.toString(QStringLiteral("HHmm")); } else { str += offsetTime.toString(QStringLiteral("HH:mm")); } } return str; } QString VCardTool::createDate(const QDate &date, VCard::Version version) { QString format; if (date.year() > 0) { format = QStringLiteral("yyyyMMdd"); } else { format = QStringLiteral("--MMdd"); } if (version != VCard::v4_0) { format = format.replace(QStringLiteral("yyyy"), QStringLiteral("yyyy-")); format = format.replace(QStringLiteral("MM"), QStringLiteral("MM-")); } return date.toString(format); } QString VCardTool::createTime(const QTime &time, VCard::Version version) { QString format; if (version == VCard::v4_0) { format = QStringLiteral("HHmmss"); } else { format = QStringLiteral("HH:mm:ss"); } return QLatin1Char('T') + time.toString(format); } Picture VCardTool::parsePicture(const VCardLine &line) const { Picture pic; const QStringList params = line.parameterList(); QString type; if (params.contains(QLatin1String("type"))) { type = line.parameter(QStringLiteral("type")); } if (params.contains(QLatin1String("encoding"))) { pic.setRawData(line.value().toByteArray(), type); } else if (params.contains(QLatin1String("value"))) { if (line.parameter(QStringLiteral("value")).toLower() == QLatin1String("uri")) { pic.setUrl(line.value().toString()); } } return pic; } VCardLine VCardTool::createPicture(const QString &identifier, const Picture &pic, VCard::Version version) const { VCardLine line(identifier); if (pic.isEmpty()) { return line; } if (pic.isIntern()) { line.setValue(pic.rawData()); if (version == VCard::v2_1) { line.addParameter(QStringLiteral("ENCODING"), QStringLiteral("BASE64")); line.addParameter(pic.type(), QString()); } else { /*if (version == VCard::v3_0) */ line.addParameter(QStringLiteral("encoding"), QStringLiteral("b")); line.addParameter(QStringLiteral("type"), pic.type()); #if 0 } else { //version 4.0 line.addParameter(QStringLiteral("data") + QStringLiteral(":image/") + pic.type(), QStringLiteral("base64")); #endif } } else { line.setValue(pic.url()); line.addParameter(QStringLiteral("value"), QStringLiteral("URI")); } return line; } Sound VCardTool::parseSound(const VCardLine &line) const { Sound snd; const QStringList params = line.parameterList(); if (params.contains(QLatin1String("encoding"))) { snd.setData(line.value().toByteArray()); } else if (params.contains(QLatin1String("value"))) { if (line.parameter(QStringLiteral("value")).toLower() == QLatin1String("uri")) { snd.setUrl(line.value().toString()); } } /* TODO: support sound types if ( params.contains( "type" ) ) snd.setType( line.parameter( "type" ) ); */ return snd; } VCardLine VCardTool::createSound(const Sound &snd, VCard::Version version) const { Q_UNUSED(version); VCardLine line(QStringLiteral("SOUND")); if (snd.isIntern()) { if (!snd.data().isEmpty()) { line.setValue(snd.data()); if (version == VCard::v2_1) { line.addParameter(QStringLiteral("ENCODING"), QStringLiteral("BASE64")); } else { line.addParameter(QStringLiteral("encoding"), QStringLiteral("b")); } // TODO: need to store sound type!!! } } else if (!snd.url().isEmpty()) { line.setValue(snd.url()); line.addParameter(QStringLiteral("value"), QStringLiteral("URI")); } return line; } Key VCardTool::parseKey(const VCardLine &line) const { Key key; const QStringList params = line.parameterList(); if (params.contains(QLatin1String("encoding"))) { key.setBinaryData(line.value().toByteArray()); } else { key.setTextData(line.value().toString()); } if (params.contains(QLatin1String("type"))) { if (line.parameter(QStringLiteral("type")).toLower() == QLatin1String("x509")) { key.setType(Key::X509); } else if (line.parameter(QStringLiteral("type")).toLower() == QLatin1String("pgp")) { key.setType(Key::PGP); } else { key.setType(Key::Custom); key.setCustomTypeString(line.parameter(QStringLiteral("type"))); } } else if (params.contains(QLatin1String("mediatype"))) { const QString param = line.parameter(QStringLiteral("mediatype")).toLower(); if (param == QLatin1String("application/x-x509-ca-cert")) { key.setType(Key::X509); } else if (param == QLatin1String("application/pgp-keys")) { key.setType(Key::PGP); } else { key.setType(Key::Custom); key.setCustomTypeString(line.parameter(QStringLiteral("type"))); } } return key; } VCardLine VCardTool::createKey(const Key &key, VCard::Version version) const { VCardLine line(QStringLiteral("KEY")); if (key.isBinary()) { if (!key.binaryData().isEmpty()) { line.setValue(key.binaryData()); if (version == VCard::v2_1) { line.addParameter(QStringLiteral("ENCODING"), QStringLiteral("BASE64")); } else { line.addParameter(QStringLiteral("encoding"), QStringLiteral("b")); } } } else if (!key.textData().isEmpty()) { line.setValue(key.textData()); } if (version == VCard::v4_0) { if (key.type() == Key::X509) { line.addParameter(QStringLiteral("MEDIATYPE"), QStringLiteral("application/x-x509-ca-cert")); } else if (key.type() == Key::PGP) { line.addParameter(QStringLiteral("MEDIATYPE"), QStringLiteral("application/pgp-keys")); } else if (key.type() == Key::Custom) { line.addParameter(QStringLiteral("MEDIATYPE"), key.customTypeString()); } } else { if (key.type() == Key::X509) { line.addParameter(QStringLiteral("type"), QStringLiteral("X509")); } else if (key.type() == Key::PGP) { line.addParameter(QStringLiteral("type"), QStringLiteral("PGP")); } else if (key.type() == Key::Custom) { line.addParameter(QStringLiteral("type"), key.customTypeString()); } } return line; } Secrecy VCardTool::parseSecrecy(const VCardLine &line) const { Secrecy secrecy; const QString value = line.value().toString().toLower(); if (value == QLatin1String("public")) { secrecy.setType(Secrecy::Public); } else if (value == QLatin1String("private")) { secrecy.setType(Secrecy::Private); } else if (value == QLatin1String("confidential")) { secrecy.setType(Secrecy::Confidential); } return secrecy; } VCardLine VCardTool::createSecrecy(const Secrecy &secrecy) const { VCardLine line(QStringLiteral("CLASS")); int type = secrecy.type(); if (type == Secrecy::Public) { line.setValue(QStringLiteral("PUBLIC")); } else if (type == Secrecy::Private) { line.setValue(QStringLiteral("PRIVATE")); } else if (type == Secrecy::Confidential) { line.setValue(QStringLiteral("CONFIDENTIAL")); } return line; } QStringList VCardTool::splitString(QChar sep, const QString &str) const { QStringList list; QString value(str); int start = 0; int pos = value.indexOf(sep, start); while (pos != -1) { if (pos == 0 || value[ pos - 1 ] != QLatin1Char('\\')) { if (pos > start && pos <= value.length()) { list << value.mid(start, pos - start); } else { list << QString(); } start = pos + 1; pos = value.indexOf(sep, start); } else { value.replace(pos - 1, 2, sep); pos = value.indexOf(sep, pos); } } int l = value.length() - 1; const QString mid = value.mid(start, l - start + 1); if (!mid.isEmpty()) { list << mid; } else { list << QString(); } return list; } QString VCardTool::normalizeImppServiceType(const QString &serviceType) const { if (serviceType == QLatin1String("jabber")) { return QStringLiteral("xmpp"); } if (serviceType == QLatin1String("yahoo")) { return QStringLiteral("ymsgr"); } if (serviceType == QLatin1String("gadugadu")) { return QStringLiteral("gg"); } return serviceType; }