File indexing completed on 2025-02-02 10:55:41
0001 /* 0002 This file is part of the KContacts framework. 0003 SPDX-FileCopyrightText: 2001 Cornelius Schumacher <schumacher@kde.org> 0004 SPDX-FileCopyrightText: 2003 Carsten Pfeiffer <pfeiffer@kde.org> 0005 SPDX-FileCopyrightText: 2005 Ingo Kloecker <kloecker@kde.org> 0006 0007 SPDX-License-Identifier: LGPL-2.0-or-later 0008 */ 0009 0010 #include <QDate> 0011 #include <QRegularExpression> 0012 #include <QSharedData> 0013 #include <QUuid> 0014 0015 #include "kcontacts_debug.h" 0016 #include <KLocalizedString> 0017 0018 #include "addressee.h" 0019 #include "addresseehelper.h" 0020 #include "field.h" 0021 #include "parametermap_p.h" 0022 0023 using namespace KContacts; 0024 0025 static bool matchBinaryPattern(int value, int pattern); 0026 0027 template<class L> 0028 static bool listEquals(const QVector<L> &list, const QVector<L> &pattern); 0029 static bool listEquals(const QStringList &list, const QStringList &pattern); 0030 0031 struct CustomData { 0032 QString name; 0033 QString value; 0034 }; 0035 0036 inline bool operator==(const CustomData &a, const CustomData &b) 0037 { 0038 return std::tie(a.name, a.value) == std::tie(b.name, b.value); 0039 } 0040 0041 inline bool operator!=(const CustomData &a, const CustomData &b) 0042 { 0043 return std::tie(a.name, a.value) != std::tie(b.name, b.value); 0044 } 0045 0046 inline bool operator<(const CustomData &a, const CustomData &b) 0047 { 0048 return a.name < b.name; 0049 } 0050 0051 class Q_DECL_HIDDEN Addressee::Private : public QSharedData 0052 { 0053 public: 0054 Private() 0055 : mUid(QUuid::createUuid().toString().mid(1, 36)) 0056 , mEmpty(true) 0057 , mChanged(false) 0058 , mBirthdayWithTime(false) 0059 { 0060 // We avoid the curly braces so the string is RFC4122 compliant and can be used as urn 0061 } 0062 0063 Private(const Private &other) 0064 : QSharedData(other) 0065 { 0066 mUid = other.mUid; 0067 mName = other.mName; 0068 mFormattedName = other.mFormattedName; 0069 mFamilyName = other.mFamilyName; 0070 mGivenName = other.mGivenName; 0071 mAdditionalName = other.mAdditionalName; 0072 mPrefix = other.mPrefix; 0073 mSuffix = other.mSuffix; 0074 mBirthday = other.mBirthday; 0075 mBirthdayWithTime = other.mBirthdayWithTime; 0076 mMailer = other.mMailer; 0077 mTimeZone = other.mTimeZone; 0078 mGeo = other.mGeo; 0079 mDepartment = other.mDepartment; 0080 mNote = other.mNote; 0081 mProductId = other.mProductId; 0082 mRevision = other.mRevision; 0083 mSortString = other.mSortString; 0084 mSecrecy = other.mSecrecy; 0085 mLogo = other.mLogo; 0086 mPhoto = other.mPhoto; 0087 mSound = other.mSound; 0088 0089 mPhoneNumbers = other.mPhoneNumbers; 0090 mAddresses = other.mAddresses; 0091 mKeys = other.mKeys; 0092 mLangs = other.mLangs; 0093 mGender = other.mGender; 0094 mEmails = other.mEmails; 0095 mCategories = other.mCategories; 0096 mCustomFields = other.mCustomFields; 0097 mCalendarUrl = other.mCalendarUrl; 0098 mSoundListExtra = other.mSoundListExtra; 0099 mPhotoExtraList = other.mPhotoExtraList; 0100 mLogoExtraList = other.mLogoExtraList; 0101 mUrlExtraList = other.mUrlExtraList; 0102 mMembers = other.mMembers; 0103 mRelationships = other.mRelationships; 0104 mSources = other.mSources; 0105 mEmpty = other.mEmpty; 0106 mImpps = other.mImpps; 0107 mChanged = other.mChanged; 0108 mTitleExtraList = other.mTitleExtraList; 0109 mRoleExtraList = other.mRoleExtraList; 0110 mOrgExtraList = other.mOrgExtraList; 0111 } 0112 0113 ~Private() 0114 { 0115 } 0116 0117 std::vector<CustomData>::iterator findByName(const QString &qualifiedName) 0118 { 0119 return std::find_if(mCustomFields.begin(), mCustomFields.end(), [&qualifiedName](const CustomData &info) { 0120 return info.name == qualifiedName; 0121 }); 0122 } 0123 0124 std::vector<CustomData>::const_iterator findByName(const QString &qualifiedName) const 0125 { 0126 return std::find_if(mCustomFields.cbegin(), mCustomFields.cend(), [&qualifiedName](const CustomData &info) { 0127 return info.name == qualifiedName; 0128 }); 0129 } 0130 0131 QString mUid; 0132 QString mName; 0133 QString mFormattedName; 0134 QString mFamilyName; 0135 QString mGivenName; 0136 QString mAdditionalName; 0137 QString mPrefix; 0138 QString mSuffix; 0139 QDateTime mBirthday; 0140 QString mMailer; 0141 TimeZone mTimeZone; 0142 Geo mGeo; 0143 QString mDepartment; 0144 QString mNote; 0145 QString mProductId; 0146 QDateTime mRevision; 0147 QString mSortString; 0148 Secrecy mSecrecy; 0149 Picture mLogo; 0150 Picture mPhoto; 0151 Sound mSound; 0152 0153 PhoneNumber::List mPhoneNumbers; 0154 Address::List mAddresses; 0155 Key::List mKeys; 0156 Email::List mEmails; 0157 Lang::List mLangs; 0158 Impp::List mImpps; 0159 Gender mGender; 0160 QString mKind; 0161 QStringList mCategories; 0162 std::vector<CustomData> mCustomFields; 0163 CalendarUrl::List mCalendarUrl; 0164 Sound::List mSoundListExtra; 0165 Picture::List mPhotoExtraList; 0166 Picture::List mLogoExtraList; 0167 ResourceLocatorUrl::List mUrlExtraList; 0168 QVector<QUrl> mSources; 0169 QStringList mMembers; 0170 Related::List mRelationships; 0171 FieldGroup::List mFieldGroupList; 0172 Title::List mTitleExtraList; 0173 Role::List mRoleExtraList; 0174 Org::List mOrgExtraList; 0175 NickName::List mNickNameExtraList; 0176 ClientPidMap::List mClientPidMapList; 0177 bool mEmpty : 1; 0178 bool mChanged : 1; 0179 bool mBirthdayWithTime; 0180 }; 0181 0182 Addressee::Addressee() 0183 : d(new Private) 0184 { 0185 } 0186 0187 Addressee::~Addressee() 0188 { 0189 } 0190 0191 Addressee::Addressee(const Addressee &other) 0192 : d(other.d) 0193 { 0194 } 0195 0196 Addressee &Addressee::operator=(const Addressee &other) 0197 { 0198 if (this != &other) { 0199 d = other.d; 0200 } 0201 0202 return *this; 0203 } 0204 0205 bool Addressee::operator==(const Addressee &addressee) const 0206 { 0207 if (d->mUid != addressee.d->mUid) { 0208 qCDebug(KCONTACTS_LOG) << "uid differs"; 0209 return false; 0210 } 0211 0212 if (d->mName != addressee.d->mName // 0213 && !(d->mName.isEmpty() && addressee.d->mName.isEmpty())) { 0214 qCDebug(KCONTACTS_LOG) << "name differs"; 0215 return false; 0216 } 0217 0218 if (d->mFormattedName != addressee.d->mFormattedName // 0219 && !(d->mFormattedName.isEmpty() && addressee.d->mFormattedName.isEmpty())) { 0220 qCDebug(KCONTACTS_LOG) << "formattedName differs"; 0221 return false; 0222 } 0223 0224 if (d->mFamilyName != addressee.d->mFamilyName // 0225 && !(d->mFamilyName.isEmpty() && addressee.d->mFamilyName.isEmpty())) { 0226 qCDebug(KCONTACTS_LOG) << "familyName differs"; 0227 return false; 0228 } 0229 0230 if (d->mGivenName != addressee.d->mGivenName // 0231 && !(d->mGivenName.isEmpty() && addressee.d->mGivenName.isEmpty())) { 0232 qCDebug(KCONTACTS_LOG) << "givenName differs"; 0233 return false; 0234 } 0235 0236 if (d->mAdditionalName != addressee.d->mAdditionalName // 0237 && !(d->mAdditionalName.isEmpty() && addressee.d->mAdditionalName.isEmpty())) { 0238 qCDebug(KCONTACTS_LOG) << "additionalName differs"; 0239 return false; 0240 } 0241 0242 if (d->mPrefix != addressee.d->mPrefix // 0243 && !(d->mPrefix.isEmpty() && addressee.d->mPrefix.isEmpty())) { 0244 qCDebug(KCONTACTS_LOG) << "prefix differs"; 0245 return false; 0246 } 0247 0248 if (d->mSuffix != addressee.d->mSuffix // 0249 && !(d->mSuffix.isEmpty() && addressee.d->mSuffix.isEmpty())) { 0250 qCDebug(KCONTACTS_LOG) << "suffix differs"; 0251 return false; 0252 } 0253 0254 if (d->mBirthday != addressee.d->mBirthday // 0255 || d->mBirthdayWithTime != addressee.d->mBirthdayWithTime) { 0256 qCDebug(KCONTACTS_LOG) << "birthday differs"; 0257 return false; 0258 } 0259 0260 if (d->mMailer != addressee.d->mMailer // 0261 && !(d->mMailer.isEmpty() && addressee.d->mMailer.isEmpty())) { 0262 qCDebug(KCONTACTS_LOG) << "mailer differs"; 0263 return false; 0264 } 0265 0266 if (d->mTimeZone != addressee.d->mTimeZone) { 0267 qCDebug(KCONTACTS_LOG) << "timeZone differs"; 0268 return false; 0269 } 0270 0271 if (d->mGeo != addressee.d->mGeo) { 0272 qCDebug(KCONTACTS_LOG) << "geo differs"; 0273 return false; 0274 } 0275 0276 if (d->mDepartment != addressee.d->mDepartment // 0277 && !(d->mDepartment.isEmpty() && addressee.d->mDepartment.isEmpty())) { 0278 qCDebug(KCONTACTS_LOG) << "department differs"; 0279 return false; 0280 } 0281 0282 if (d->mNote != addressee.d->mNote // 0283 && !(d->mNote.isEmpty() && addressee.d->mNote.isEmpty())) { 0284 qCDebug(KCONTACTS_LOG) << "note differs"; 0285 return false; 0286 } 0287 0288 if (d->mProductId != addressee.d->mProductId // 0289 && !(d->mProductId.isEmpty() && addressee.d->mProductId.isEmpty())) { 0290 qCDebug(KCONTACTS_LOG) << "productId differs"; 0291 return false; 0292 } 0293 0294 if (d->mSortString != addressee.d->mSortString // 0295 && !(d->mSortString.isEmpty() && addressee.d->mSortString.isEmpty())) { 0296 qCDebug(KCONTACTS_LOG) << "sortString differs"; 0297 return false; 0298 } 0299 0300 if (d->mSecrecy != addressee.d->mSecrecy) { 0301 qCDebug(KCONTACTS_LOG) << "secrecy differs"; 0302 return false; 0303 } 0304 0305 if (d->mLogo != addressee.d->mLogo) { 0306 qCDebug(KCONTACTS_LOG) << "logo differs"; 0307 return false; 0308 } 0309 0310 if (d->mPhoto != addressee.d->mPhoto) { 0311 qCDebug(KCONTACTS_LOG) << "photo differs"; 0312 return false; 0313 } 0314 0315 if (d->mSound != addressee.d->mSound) { 0316 qCDebug(KCONTACTS_LOG) << "sound differs"; 0317 return false; 0318 } 0319 0320 if (!listEquals(d->mPhoneNumbers, addressee.d->mPhoneNumbers)) { 0321 qCDebug(KCONTACTS_LOG) << "phoneNumbers differs"; 0322 return false; 0323 } 0324 0325 if (!listEquals(d->mAddresses, addressee.d->mAddresses)) { 0326 qCDebug(KCONTACTS_LOG) << "addresses differs"; 0327 return false; 0328 } 0329 0330 if (!listEquals(d->mKeys, addressee.d->mKeys)) { 0331 qCDebug(KCONTACTS_LOG) << "keys differs"; 0332 return false; 0333 } 0334 if (!listEquals(d->mEmails, addressee.d->mEmails)) { 0335 qCDebug(KCONTACTS_LOG) << "emails differs"; 0336 return false; 0337 } 0338 0339 if (!listEquals(d->mCategories, addressee.d->mCategories)) { 0340 qCDebug(KCONTACTS_LOG) << "categories differs"; 0341 return false; 0342 } 0343 0344 if (d->mCustomFields != addressee.d->mCustomFields) { 0345 qCDebug(KCONTACTS_LOG) << "custom differs"; 0346 return false; 0347 } 0348 if (d->mLangs != addressee.d->mLangs) { 0349 qCDebug(KCONTACTS_LOG) << "langs differs"; 0350 return false; 0351 } 0352 if (d->mImpps != addressee.d->mImpps) { 0353 qCDebug(KCONTACTS_LOG) << "impps differs"; 0354 return false; 0355 } 0356 if (d->mGender != addressee.d->mGender) { 0357 qCDebug(KCONTACTS_LOG) << "gender differs"; 0358 return false; 0359 } 0360 if (d->mKind != addressee.d->mKind) { 0361 qCDebug(KCONTACTS_LOG) << "kind differs"; 0362 return false; 0363 } 0364 if (!listEquals(d->mCalendarUrl, addressee.d->mCalendarUrl)) { 0365 qCDebug(KCONTACTS_LOG) << "calendarUrl differs"; 0366 return false; 0367 } 0368 if (!listEquals(d->mSoundListExtra, addressee.d->mSoundListExtra)) { 0369 qCDebug(KCONTACTS_LOG) << "Extra sound differs"; 0370 return false; 0371 } 0372 if (!listEquals(d->mPhotoExtraList, addressee.d->mPhotoExtraList)) { 0373 qCDebug(KCONTACTS_LOG) << "Extra photo differs"; 0374 return false; 0375 } 0376 if (!listEquals(d->mLogoExtraList, addressee.d->mLogoExtraList)) { 0377 qCDebug(KCONTACTS_LOG) << "Extra logo differs"; 0378 return false; 0379 } 0380 if (!listEquals(d->mUrlExtraList, addressee.d->mUrlExtraList)) { 0381 qCDebug(KCONTACTS_LOG) << "Extra url differs"; 0382 return false; 0383 } 0384 if (!listEquals(d->mMembers, addressee.d->mMembers)) { 0385 qCDebug(KCONTACTS_LOG) << "Extra url differs"; 0386 return false; 0387 } 0388 if (!listEquals(d->mRelationships, addressee.d->mRelationships)) { 0389 qCDebug(KCONTACTS_LOG) << "Relationships differs"; 0390 return false; 0391 } 0392 if (!listEquals(d->mSources, addressee.d->mSources)) { 0393 qCDebug(KCONTACTS_LOG) << "Sources differs"; 0394 return false; 0395 } 0396 0397 if (!listEquals(d->mFieldGroupList, addressee.d->mFieldGroupList)) { 0398 qCDebug(KCONTACTS_LOG) << "Field Groups differs"; 0399 return false; 0400 } 0401 0402 if (!listEquals(d->mTitleExtraList, addressee.d->mTitleExtraList)) { 0403 qCDebug(KCONTACTS_LOG) << "Extra TitleList differs"; 0404 return false; 0405 } 0406 0407 if (!listEquals(d->mRoleExtraList, addressee.d->mRoleExtraList)) { 0408 qCDebug(KCONTACTS_LOG) << "Extra RoleList differs"; 0409 return false; 0410 } 0411 0412 if (!listEquals(d->mOrgExtraList, addressee.d->mOrgExtraList)) { 0413 qCDebug(KCONTACTS_LOG) << "Extra Organization List differs"; 0414 return false; 0415 } 0416 0417 if (!listEquals(d->mNickNameExtraList, addressee.d->mNickNameExtraList)) { 0418 qCDebug(KCONTACTS_LOG) << "Extra NickName List differs"; 0419 return false; 0420 } 0421 0422 if (!listEquals(d->mClientPidMapList, addressee.d->mClientPidMapList)) { 0423 qCDebug(KCONTACTS_LOG) << "ClientPidMap List differs"; 0424 return false; 0425 } 0426 return true; 0427 } 0428 0429 bool Addressee::operator!=(const Addressee &a) const 0430 { 0431 return !(a == *this); 0432 } 0433 0434 bool Addressee::isEmpty() const 0435 { 0436 return d->mEmpty; 0437 } 0438 0439 void Addressee::setUid(const QString &id) 0440 { 0441 if (id == d->mUid) { 0442 return; 0443 } 0444 0445 d->mEmpty = false; 0446 d->mUid = id; 0447 } 0448 0449 QString Addressee::uid() const 0450 { 0451 return d->mUid; 0452 } 0453 0454 QString Addressee::uidLabel() 0455 { 0456 return i18n("Unique Identifier"); 0457 } 0458 0459 void Addressee::setName(const QString &name) 0460 { 0461 if (name == d->mName) { 0462 return; 0463 } 0464 0465 d->mEmpty = false; 0466 d->mName = name; 0467 } 0468 0469 QString Addressee::name() const 0470 { 0471 return d->mName; 0472 } 0473 0474 QString Addressee::nameLabel() 0475 { 0476 return i18n("Name"); 0477 } 0478 0479 void Addressee::setKind(const QString &kind) 0480 { 0481 if (kind == d->mKind) { 0482 return; 0483 } 0484 0485 d->mEmpty = false; 0486 d->mKind = kind; 0487 } 0488 0489 QString Addressee::kind() const 0490 { 0491 return d->mKind; 0492 } 0493 0494 void Addressee::insertExtraSound(const Sound &sound) 0495 { 0496 d->mEmpty = false; 0497 d->mSoundListExtra.append(sound); 0498 } 0499 0500 Sound::List Addressee::extraSoundList() const 0501 { 0502 return d->mSoundListExtra; 0503 } 0504 0505 void Addressee::insertExtraPhoto(const Picture &picture) 0506 { 0507 d->mEmpty = false; 0508 d->mPhotoExtraList.append(picture); 0509 } 0510 0511 Picture::List Addressee::extraPhotoList() const 0512 { 0513 return d->mPhotoExtraList; 0514 } 0515 0516 void Addressee::insertExtraLogo(const Picture &logo) 0517 { 0518 d->mEmpty = false; 0519 d->mLogoExtraList.append(logo); 0520 } 0521 0522 Picture::List Addressee::extraLogoList() const 0523 { 0524 return d->mLogoExtraList; 0525 } 0526 0527 void Addressee::setExtraSoundList(const Sound::List &soundList) 0528 { 0529 d->mEmpty = false; 0530 d->mSoundListExtra = soundList; 0531 } 0532 0533 void Addressee::setExtraPhotoList(const Picture::List &pictureList) 0534 { 0535 d->mEmpty = false; 0536 d->mPhotoExtraList = pictureList; 0537 } 0538 0539 void Addressee::setExtraLogoList(const Picture::List &logoList) 0540 { 0541 d->mEmpty = false; 0542 d->mLogoExtraList = logoList; 0543 } 0544 0545 void Addressee::insertExtraUrl(const ResourceLocatorUrl &url) 0546 { 0547 if (url.isValid()) { 0548 d->mEmpty = false; 0549 d->mUrlExtraList.append(url); 0550 } 0551 } 0552 0553 void Addressee::setExtraUrlList(const ResourceLocatorUrl::List &urlList) 0554 { 0555 d->mEmpty = false; 0556 d->mUrlExtraList = urlList; 0557 } 0558 0559 ResourceLocatorUrl::List Addressee::extraUrlList() const 0560 { 0561 return d->mUrlExtraList; 0562 } 0563 0564 void Addressee::insertSourceUrl(const QUrl &url) 0565 { 0566 d->mEmpty = false; 0567 d->mSources.append(url); 0568 } 0569 0570 void Addressee::setSourcesUrlList(const QVector<QUrl> &urlList) 0571 { 0572 d->mEmpty = false; 0573 d->mSources = urlList; 0574 } 0575 0576 QVector<QUrl> Addressee::sourcesUrlList() const 0577 { 0578 return d->mSources; 0579 } 0580 0581 FieldGroup::List Addressee::fieldGroupList() const 0582 { 0583 return d->mFieldGroupList; 0584 } 0585 0586 void Addressee::setFieldGroupList(const FieldGroup::List &fieldGroupList) 0587 { 0588 d->mEmpty = false; 0589 d->mFieldGroupList = fieldGroupList; 0590 } 0591 0592 void Addressee::insertFieldGroup(const FieldGroup &fieldGroup) 0593 { 0594 if (fieldGroup.isValid()) { 0595 d->mEmpty = false; 0596 // TODO don't duplicate ? 0597 d->mFieldGroupList.append(fieldGroup); 0598 } 0599 } 0600 0601 ClientPidMap::List Addressee::clientPidMapList() const 0602 { 0603 return d->mClientPidMapList; 0604 } 0605 0606 void Addressee::setClientPidMapList(const ClientPidMap::List &clientpidmaplist) 0607 { 0608 d->mEmpty = false; 0609 d->mClientPidMapList = clientpidmaplist; 0610 } 0611 0612 void Addressee::insertClientPidMap(const ClientPidMap &clientpidmap) 0613 { 0614 if (clientpidmap.isValid()) { 0615 d->mEmpty = false; 0616 // TODO don't duplicate ? 0617 d->mClientPidMapList.append(clientpidmap); 0618 } 0619 } 0620 0621 void Addressee::insertImpp(const Impp &impp) 0622 { 0623 if (impp.isValid()) { 0624 d->mEmpty = false; 0625 // Don't duplicate ? 0626 d->mImpps.append(impp); 0627 } 0628 } 0629 0630 void Addressee::setImppList(const Impp::List &imppList) 0631 { 0632 d->mEmpty = false; 0633 d->mImpps = imppList; 0634 } 0635 0636 Impp::List Addressee::imppList() const 0637 { 0638 return d->mImpps; 0639 } 0640 0641 void Addressee::insertCalendarUrl(const CalendarUrl &calendarUrl) 0642 { 0643 d->mEmpty = false; 0644 // TODO verify that there is not same calendarurl 0645 if (calendarUrl.isValid()) { 0646 d->mCalendarUrl.append(calendarUrl); 0647 } 0648 } 0649 0650 CalendarUrl::List Addressee::calendarUrlList() const 0651 { 0652 return d->mCalendarUrl; 0653 } 0654 0655 void Addressee::setFormattedName(const QString &formattedName) 0656 { 0657 if (formattedName == d->mFormattedName) { 0658 return; 0659 } 0660 0661 d->mEmpty = false; 0662 d->mFormattedName = formattedName; 0663 } 0664 0665 QString Addressee::formattedName() const 0666 { 0667 return d->mFormattedName; 0668 } 0669 0670 QString Addressee::formattedNameLabel() 0671 { 0672 return i18n("Formatted Name"); 0673 } 0674 0675 void Addressee::setFamilyName(const QString &familyName) 0676 { 0677 if (familyName == d->mFamilyName) { 0678 return; 0679 } 0680 0681 d->mEmpty = false; 0682 d->mFamilyName = familyName; 0683 } 0684 0685 QString Addressee::familyName() const 0686 { 0687 return d->mFamilyName; 0688 } 0689 0690 QString Addressee::familyNameLabel() 0691 { 0692 return i18n("Family Name"); 0693 } 0694 0695 void Addressee::setGivenName(const QString &givenName) 0696 { 0697 if (givenName == d->mGivenName) { 0698 return; 0699 } 0700 0701 d->mEmpty = false; 0702 d->mGivenName = givenName; 0703 } 0704 0705 QString Addressee::givenName() const 0706 { 0707 return d->mGivenName; 0708 } 0709 0710 QString Addressee::givenNameLabel() 0711 { 0712 return i18n("Given Name"); 0713 } 0714 0715 void Addressee::setAdditionalName(const QString &additionalName) 0716 { 0717 if (additionalName == d->mAdditionalName) { 0718 return; 0719 } 0720 0721 d->mEmpty = false; 0722 d->mAdditionalName = additionalName; 0723 } 0724 0725 QString Addressee::additionalName() const 0726 { 0727 return d->mAdditionalName; 0728 } 0729 0730 QString Addressee::additionalNameLabel() 0731 { 0732 return i18n("Additional Names"); 0733 } 0734 0735 void Addressee::setPrefix(const QString &prefix) 0736 { 0737 if (prefix == d->mPrefix) { 0738 return; 0739 } 0740 0741 d->mEmpty = false; 0742 d->mPrefix = prefix; 0743 } 0744 0745 QString Addressee::prefix() const 0746 { 0747 return d->mPrefix; 0748 } 0749 0750 QString Addressee::prefixLabel() 0751 { 0752 return i18n("Honorific Prefixes"); 0753 } 0754 0755 void Addressee::setSuffix(const QString &suffix) 0756 { 0757 if (suffix == d->mSuffix) { 0758 return; 0759 } 0760 0761 d->mEmpty = false; 0762 d->mSuffix = suffix; 0763 } 0764 0765 QString Addressee::suffix() const 0766 { 0767 return d->mSuffix; 0768 } 0769 0770 QString Addressee::suffixLabel() 0771 { 0772 return i18n("Honorific Suffixes"); 0773 } 0774 0775 void Addressee::setNickName(const QString &nickName) 0776 { 0777 NickName t(nickName); 0778 if (!d->mNickNameExtraList.isEmpty()) { 0779 t = d->mNickNameExtraList.takeFirst(); 0780 t.setNickName(nickName); 0781 d->mNickNameExtraList.prepend(t); 0782 d->mEmpty = false; 0783 } else { 0784 insertExtraNickName(t); 0785 } 0786 } 0787 0788 void Addressee::setNickName(const NickName &nickName) 0789 { 0790 insertExtraNickName(nickName); 0791 } 0792 0793 void Addressee::insertExtraNickName(const NickName &nickName) 0794 { 0795 if (nickName.isValid()) { 0796 d->mEmpty = false; 0797 d->mNickNameExtraList.append(nickName); 0798 } 0799 } 0800 0801 void Addressee::setExtraNickNameList(const NickName::List &nickNameList) 0802 { 0803 d->mEmpty = false; 0804 d->mNickNameExtraList = nickNameList; 0805 } 0806 0807 NickName::List Addressee::extraNickNameList() const 0808 { 0809 return d->mNickNameExtraList; 0810 } 0811 0812 QString Addressee::nickName() const 0813 { 0814 if (d->mNickNameExtraList.isEmpty()) { 0815 return {}; 0816 } else { 0817 return d->mNickNameExtraList.at(0).nickname(); 0818 } 0819 } 0820 0821 QString Addressee::nickNameLabel() 0822 { 0823 return i18n("Nick Name"); 0824 } 0825 0826 void Addressee::setBirthday(const QDateTime &birthday, bool withTime) 0827 { 0828 if (birthday == d->mBirthday && d->mBirthdayWithTime == withTime) { 0829 return; 0830 } 0831 0832 d->mEmpty = false; 0833 d->mBirthday = birthday; 0834 if (!withTime) { 0835 d->mBirthday.setTime(QTime()); 0836 } 0837 d->mBirthdayWithTime = withTime; 0838 } 0839 0840 void Addressee::setBirthday(const QDate &birthday) 0841 { 0842 if (birthday == d->mBirthday.date() && !d->mBirthdayWithTime) { 0843 return; 0844 } 0845 0846 d->mEmpty = false; 0847 d->mBirthday = QDateTime(birthday, QTime()); 0848 d->mBirthdayWithTime = false; 0849 } 0850 0851 QDateTime Addressee::birthday() const 0852 { 0853 return d->mBirthday; 0854 } 0855 0856 bool Addressee::birthdayHasTime() const 0857 { 0858 return d->mBirthdayWithTime; 0859 } 0860 0861 QString Addressee::birthdayLabel() 0862 { 0863 return i18n("Birthday"); 0864 } 0865 0866 QString Addressee::homeAddressStreetLabel() 0867 { 0868 return i18n("Home Address Street"); 0869 } 0870 0871 QString Addressee::homeAddressPostOfficeBoxLabel() 0872 { 0873 return i18n("Home Address Post Office Box"); 0874 } 0875 0876 QString Addressee::homeAddressLocalityLabel() 0877 { 0878 return i18n("Home Address City"); 0879 } 0880 0881 QString Addressee::homeAddressRegionLabel() 0882 { 0883 return i18n("Home Address State"); 0884 } 0885 0886 QString Addressee::homeAddressPostalCodeLabel() 0887 { 0888 return i18n("Home Address Zip Code"); 0889 } 0890 0891 QString Addressee::homeAddressCountryLabel() 0892 { 0893 return i18n("Home Address Country"); 0894 } 0895 0896 QString Addressee::homeAddressLabelLabel() 0897 { 0898 return i18n("Home Address Label"); 0899 } 0900 0901 QString Addressee::businessAddressStreetLabel() 0902 { 0903 return i18n("Business Address Street"); 0904 } 0905 0906 QString Addressee::businessAddressPostOfficeBoxLabel() 0907 { 0908 return i18n("Business Address Post Office Box"); 0909 } 0910 0911 QString Addressee::businessAddressLocalityLabel() 0912 { 0913 return i18n("Business Address City"); 0914 } 0915 0916 QString Addressee::businessAddressRegionLabel() 0917 { 0918 return i18n("Business Address State"); 0919 } 0920 0921 QString Addressee::businessAddressPostalCodeLabel() 0922 { 0923 return i18n("Business Address Zip Code"); 0924 } 0925 0926 QString Addressee::businessAddressCountryLabel() 0927 { 0928 return i18n("Business Address Country"); 0929 } 0930 0931 QString Addressee::businessAddressLabelLabel() 0932 { 0933 return i18n("Business Address Label"); 0934 } 0935 0936 QString Addressee::homePhoneLabel() 0937 { 0938 return i18n("Home Phone"); 0939 } 0940 0941 QString Addressee::businessPhoneLabel() 0942 { 0943 return i18n("Business Phone"); 0944 } 0945 0946 QString Addressee::mobilePhoneLabel() 0947 { 0948 return i18n("Mobile Phone"); 0949 } 0950 0951 QString Addressee::homeFaxLabel() 0952 { 0953 return i18n("Home Fax"); 0954 } 0955 0956 QString Addressee::businessFaxLabel() 0957 { 0958 return i18n("Business Fax"); 0959 } 0960 0961 QString Addressee::carPhoneLabel() 0962 { 0963 return i18n("Car Phone"); 0964 } 0965 0966 QString Addressee::isdnLabel() 0967 { 0968 return i18n("ISDN"); 0969 } 0970 0971 QString Addressee::pagerLabel() 0972 { 0973 return i18n("Pager"); 0974 } 0975 0976 QString Addressee::emailLabel() 0977 { 0978 return i18n("Email Address"); 0979 } 0980 0981 void Addressee::setMailer(const QString &mailer) 0982 { 0983 if (mailer == d->mMailer) { 0984 return; 0985 } 0986 0987 d->mEmpty = false; 0988 d->mMailer = mailer; 0989 } 0990 0991 QString Addressee::mailer() const 0992 { 0993 return d->mMailer; 0994 } 0995 0996 QString Addressee::mailerLabel() 0997 { 0998 return i18n("Mail Client"); 0999 } 1000 1001 void Addressee::setTimeZone(const TimeZone &timeZone) 1002 { 1003 if (timeZone == d->mTimeZone) { 1004 return; 1005 } 1006 1007 d->mEmpty = false; 1008 d->mTimeZone = timeZone; 1009 } 1010 1011 TimeZone Addressee::timeZone() const 1012 { 1013 return d->mTimeZone; 1014 } 1015 1016 QString Addressee::timeZoneLabel() 1017 { 1018 return i18n("Time Zone"); 1019 } 1020 1021 void Addressee::setGeo(const Geo &geo) 1022 { 1023 if (geo == d->mGeo) { 1024 return; 1025 } 1026 1027 d->mEmpty = false; 1028 d->mGeo = geo; 1029 } 1030 1031 Geo Addressee::geo() const 1032 { 1033 return d->mGeo; 1034 } 1035 1036 QString Addressee::geoLabel() 1037 { 1038 return i18n("Geographic Position"); 1039 } 1040 1041 void Addressee::setTitle(const QString &title) 1042 { 1043 Title t(title); 1044 if (!d->mTitleExtraList.isEmpty()) { 1045 t = d->mTitleExtraList.takeFirst(); 1046 t.setTitle(title); 1047 d->mTitleExtraList.prepend(t); 1048 d->mEmpty = false; 1049 } else { 1050 insertExtraTitle(title); 1051 } 1052 } 1053 1054 void Addressee::setTitle(const Title &title) 1055 { 1056 insertExtraTitle(title); 1057 } 1058 1059 void Addressee::insertExtraTitle(const Title &title) 1060 { 1061 if (title.isValid()) { 1062 d->mEmpty = false; 1063 d->mTitleExtraList.append(title); 1064 } 1065 } 1066 1067 QString Addressee::title() const 1068 { 1069 if (d->mTitleExtraList.isEmpty()) { 1070 return {}; 1071 } else { 1072 return d->mTitleExtraList.at(0).title(); 1073 } 1074 } 1075 1076 Title::List Addressee::extraTitleList() const 1077 { 1078 return d->mTitleExtraList; 1079 } 1080 1081 void Addressee::setExtraTitleList(const Title::List &urltitle) 1082 { 1083 d->mEmpty = false; 1084 d->mTitleExtraList = urltitle; 1085 } 1086 1087 QString Addressee::titleLabel() 1088 { 1089 return i18nc("a person's title", "Title"); 1090 } 1091 1092 void Addressee::setRole(const QString &role) 1093 { 1094 Role t(role); 1095 if (!d->mRoleExtraList.isEmpty()) { 1096 t = d->mRoleExtraList.takeFirst(); 1097 t.setRole(role); 1098 d->mRoleExtraList.prepend(t); 1099 d->mEmpty = false; 1100 } else { 1101 insertExtraRole(t); 1102 } 1103 } 1104 1105 void Addressee::setRole(const Role &role) 1106 { 1107 insertExtraRole(role); 1108 } 1109 1110 void Addressee::insertExtraRole(const Role &role) 1111 { 1112 if (role.isValid()) { 1113 d->mEmpty = false; 1114 d->mRoleExtraList.append(role); 1115 } 1116 } 1117 1118 void Addressee::setExtraRoleList(const Role::List &roleList) 1119 { 1120 d->mEmpty = false; 1121 d->mRoleExtraList = roleList; 1122 } 1123 1124 Role::List Addressee::extraRoleList() const 1125 { 1126 return d->mRoleExtraList; 1127 } 1128 1129 QString Addressee::role() const 1130 { 1131 if (d->mRoleExtraList.isEmpty()) { 1132 return {}; 1133 } else { 1134 return d->mRoleExtraList.at(0).role(); 1135 } 1136 } 1137 1138 QString Addressee::roleLabel() 1139 { 1140 return i18nc("of a person in an organization", "Role"); 1141 } 1142 1143 void Addressee::setOrganization(const QString &organization) 1144 { 1145 Org t(organization); 1146 if (!d->mOrgExtraList.isEmpty()) { 1147 t = d->mOrgExtraList.takeFirst(); 1148 t.setOrganization(organization); 1149 d->mOrgExtraList.prepend(t); 1150 d->mEmpty = false; 1151 } else { 1152 insertExtraOrganization(t); 1153 } 1154 } 1155 1156 void Addressee::setOrganization(const Org &organization) 1157 { 1158 insertExtraOrganization(organization); 1159 } 1160 1161 void Addressee::insertExtraOrganization(const Org &organization) 1162 { 1163 if (organization.isValid()) { 1164 d->mEmpty = false; 1165 d->mOrgExtraList.append(organization); 1166 } 1167 } 1168 1169 void Addressee::setExtraOrganizationList(const Org::List &orgList) 1170 { 1171 d->mEmpty = false; 1172 d->mOrgExtraList = orgList; 1173 } 1174 1175 Org::List Addressee::extraOrganizationList() const 1176 { 1177 return d->mOrgExtraList; 1178 } 1179 1180 QString Addressee::organization() const 1181 { 1182 if (d->mOrgExtraList.isEmpty()) { 1183 return {}; 1184 } else { 1185 return d->mOrgExtraList.at(0).organization(); 1186 } 1187 } 1188 1189 QString Addressee::organizationLabel() 1190 { 1191 return i18n("Organization"); 1192 } 1193 1194 void Addressee::setDepartment(const QString &department) 1195 { 1196 if (department == d->mDepartment) { 1197 return; 1198 } 1199 1200 d->mEmpty = false; 1201 d->mDepartment = department; 1202 } 1203 1204 QString Addressee::department() const 1205 { 1206 return d->mDepartment; 1207 } 1208 1209 QString Addressee::departmentLabel() 1210 { 1211 return i18n("Department"); 1212 } 1213 1214 void Addressee::setNote(const QString ¬e) 1215 { 1216 if (note == d->mNote) { 1217 return; 1218 } 1219 1220 d->mEmpty = false; 1221 d->mNote = note; 1222 } 1223 1224 QString Addressee::note() const 1225 { 1226 return d->mNote; 1227 } 1228 1229 QString Addressee::noteLabel() 1230 { 1231 return i18n("Note"); 1232 } 1233 1234 void Addressee::setProductId(const QString &productId) 1235 { 1236 if (productId == d->mProductId) { 1237 return; 1238 } 1239 1240 d->mEmpty = false; 1241 d->mProductId = productId; 1242 } 1243 1244 QString Addressee::productId() const 1245 { 1246 return d->mProductId; 1247 } 1248 1249 QString Addressee::productIdLabel() 1250 { 1251 return i18n("Product Identifier"); 1252 } 1253 1254 void Addressee::setRevision(const QDateTime &revision) 1255 { 1256 if (revision == d->mRevision) { 1257 return; 1258 } 1259 1260 d->mEmpty = false; 1261 d->mRevision = revision; 1262 } 1263 1264 QDateTime Addressee::revision() const 1265 { 1266 return d->mRevision; 1267 } 1268 1269 QString Addressee::revisionLabel() 1270 { 1271 return i18n("Revision Date"); 1272 } 1273 1274 void Addressee::setSortString(const QString &sortString) 1275 { 1276 if (sortString == d->mSortString) { 1277 return; 1278 } 1279 1280 d->mEmpty = false; 1281 d->mSortString = sortString; 1282 } 1283 1284 QString Addressee::sortString() const 1285 { 1286 return d->mSortString; 1287 } 1288 1289 QString Addressee::sortStringLabel() 1290 { 1291 return i18n("Sort String"); 1292 } 1293 1294 void Addressee::setUrl(const QUrl &url) 1295 { 1296 KContacts::ResourceLocatorUrl resourceLocator; 1297 resourceLocator.setUrl(url); 1298 insertExtraUrl(resourceLocator); 1299 } 1300 1301 void Addressee::setUrl(const ResourceLocatorUrl &url) 1302 { 1303 insertExtraUrl(url); 1304 } 1305 1306 ResourceLocatorUrl Addressee::url() const 1307 { 1308 if (d->mUrlExtraList.isEmpty()) { 1309 return ResourceLocatorUrl(); 1310 } else { 1311 return d->mUrlExtraList.at(0); 1312 } 1313 } 1314 1315 QString Addressee::urlLabel() 1316 { 1317 return i18n("Homepage"); 1318 } 1319 1320 void Addressee::setSecrecy(const Secrecy &secrecy) 1321 { 1322 if (secrecy == d->mSecrecy) { 1323 return; 1324 } 1325 1326 d->mEmpty = false; 1327 d->mSecrecy = secrecy; 1328 } 1329 1330 Secrecy Addressee::secrecy() const 1331 { 1332 return d->mSecrecy; 1333 } 1334 1335 QString Addressee::secrecyLabel() 1336 { 1337 return i18n("Security Class"); 1338 } 1339 1340 void Addressee::setLogo(const Picture &logo) 1341 { 1342 if (logo == d->mLogo) { 1343 return; 1344 } 1345 1346 d->mEmpty = false; 1347 d->mLogo = logo; 1348 } 1349 1350 Picture Addressee::logo() const 1351 { 1352 return d->mLogo; 1353 } 1354 1355 QString Addressee::logoLabel() 1356 { 1357 return i18n("Logo"); 1358 } 1359 1360 void Addressee::setPhoto(const Picture &photo) 1361 { 1362 if (photo == d->mPhoto) { 1363 return; 1364 } 1365 1366 d->mEmpty = false; 1367 d->mPhoto = photo; 1368 } 1369 1370 Picture Addressee::photo() const 1371 { 1372 return d->mPhoto; 1373 } 1374 1375 QString Addressee::photoLabel() 1376 { 1377 return i18n("Photo"); 1378 } 1379 1380 void Addressee::setSound(const Sound &sound) 1381 { 1382 if (sound == d->mSound) { 1383 return; 1384 } 1385 1386 d->mEmpty = false; 1387 d->mSound = sound; 1388 } 1389 1390 Sound Addressee::sound() const 1391 { 1392 return d->mSound; 1393 } 1394 1395 QString Addressee::soundLabel() 1396 { 1397 return i18n("Sound"); 1398 } 1399 1400 void Addressee::setNameFromString(const QString &s) 1401 { 1402 QString str = s; 1403 // remove enclosing quotes from string 1404 if (str.length() > 1 && s[0] == QLatin1Char('"') && s[s.length() - 1] == QLatin1Char('"')) { 1405 str = s.mid(1, s.length() - 2); 1406 } 1407 1408 setFormattedName(str); 1409 setName(str); 1410 1411 // clear all name parts 1412 setPrefix(QString()); 1413 setGivenName(QString()); 1414 setAdditionalName(QString()); 1415 setFamilyName(QString()); 1416 setSuffix(QString()); 1417 1418 if (str.isEmpty()) { 1419 return; 1420 } 1421 1422 static QString spaceStr = QStringLiteral(" "); 1423 static QString emptyStr = QStringLiteral(""); 1424 AddresseeHelper *helper = AddresseeHelper::self(); 1425 1426 int i = str.indexOf(QLatin1Char(',')); 1427 if (i < 0) { 1428 QStringList parts = str.split(spaceStr); 1429 int leftOffset = 0; 1430 int rightOffset = parts.count() - 1; 1431 1432 QString suffix; 1433 while (rightOffset >= 0) { 1434 if (helper->containsSuffix(parts[rightOffset])) { 1435 suffix.prepend(parts[rightOffset] + (suffix.isEmpty() ? emptyStr : spaceStr)); 1436 rightOffset--; 1437 } else { 1438 break; 1439 } 1440 } 1441 setSuffix(suffix); 1442 1443 if (rightOffset < 0) { 1444 return; 1445 } 1446 1447 if (rightOffset - 1 >= 0 && helper->containsPrefix(parts[rightOffset - 1].toLower())) { 1448 setFamilyName(parts[rightOffset - 1] + spaceStr + parts[rightOffset]); 1449 rightOffset--; 1450 } else { 1451 if (helper->treatAsFamilyName()) { 1452 setFamilyName(parts[rightOffset]); 1453 } else { 1454 setGivenName(parts[rightOffset]); 1455 } 1456 } 1457 1458 QString prefix; 1459 while (leftOffset < rightOffset) { 1460 if (helper->containsTitle(parts[leftOffset])) { 1461 prefix.append((prefix.isEmpty() ? emptyStr : spaceStr) + parts[leftOffset]); 1462 leftOffset++; 1463 } else { 1464 break; 1465 } 1466 } 1467 setPrefix(prefix); 1468 1469 if (leftOffset < rightOffset) { 1470 setGivenName(parts[leftOffset]); 1471 leftOffset++; 1472 } 1473 1474 QString additionalName; 1475 while (leftOffset < rightOffset) { 1476 additionalName.append((additionalName.isEmpty() ? emptyStr : spaceStr) + parts[leftOffset]); 1477 leftOffset++; 1478 } 1479 setAdditionalName(additionalName); 1480 } else { 1481 QString part1 = str.left(i); 1482 QString part2 = str.mid(i + 1); 1483 1484 QStringList parts = part1.split(spaceStr); 1485 int leftOffset = 0; 1486 int rightOffset = parts.count() - 1; 1487 1488 if (!parts.isEmpty()) { 1489 QString suffix; 1490 while (rightOffset >= 0) { 1491 if (helper->containsSuffix(parts[rightOffset])) { 1492 suffix.prepend(parts[rightOffset] + (suffix.isEmpty() ? emptyStr : spaceStr)); 1493 rightOffset--; 1494 } else { 1495 break; 1496 } 1497 } 1498 setSuffix(suffix); 1499 1500 if (rightOffset - 1 >= 0 && helper->containsPrefix(parts[rightOffset - 1].toLower())) { 1501 setFamilyName(parts[rightOffset - 1] + spaceStr + parts[rightOffset]); 1502 rightOffset--; 1503 } else { 1504 setFamilyName(parts[rightOffset]); 1505 } 1506 1507 QString prefix; 1508 while (leftOffset < rightOffset) { 1509 if (helper->containsTitle(parts[leftOffset])) { 1510 prefix.append((prefix.isEmpty() ? emptyStr : spaceStr) + parts[leftOffset]); 1511 leftOffset++; 1512 } else { 1513 break; 1514 } 1515 } 1516 } else { 1517 setPrefix(QString()); 1518 setFamilyName(QString()); 1519 setSuffix(QString()); 1520 } 1521 1522 parts = part2.split(spaceStr); 1523 1524 leftOffset = 0; 1525 rightOffset = parts.count(); 1526 1527 if (!parts.isEmpty()) { 1528 QString prefix; 1529 while (leftOffset < rightOffset) { 1530 if (helper->containsTitle(parts[leftOffset])) { 1531 prefix.append((prefix.isEmpty() ? emptyStr : spaceStr) + parts[leftOffset]); 1532 leftOffset++; 1533 } else { 1534 break; 1535 } 1536 } 1537 setPrefix(prefix); 1538 1539 if (leftOffset < rightOffset) { 1540 setGivenName(parts[leftOffset]); 1541 leftOffset++; 1542 } 1543 1544 QString additionalName; 1545 while (leftOffset < rightOffset) { 1546 additionalName.append((additionalName.isEmpty() ? emptyStr : spaceStr) + parts[leftOffset]); 1547 leftOffset++; 1548 } 1549 setAdditionalName(additionalName); 1550 } else { 1551 setGivenName(QString()); 1552 setAdditionalName(QString()); 1553 } 1554 } 1555 } 1556 1557 QString Addressee::realName() const 1558 { 1559 QString n(formattedName()); 1560 if (!n.isEmpty()) { 1561 return n; 1562 } 1563 1564 n = assembledName(); 1565 if (!n.isEmpty()) { 1566 return n; 1567 } 1568 1569 n = name(); 1570 if (!n.isEmpty()) { 1571 return n; 1572 } 1573 1574 return organization(); 1575 } 1576 1577 QString Addressee::assembledName() const 1578 { 1579 // clang-format off 1580 const QString name = prefix() + QLatin1Char(' ') 1581 + givenName() + QLatin1Char(' ') 1582 + additionalName() + QLatin1Char(' ') 1583 + familyName() + QLatin1Char(' ') 1584 + suffix(); 1585 // clang-format on 1586 1587 return name.simplified(); 1588 } 1589 1590 QString Addressee::fullEmail(const QString &email) const 1591 { 1592 QString e; 1593 if (email.isNull()) { 1594 e = preferredEmail(); 1595 } else { 1596 e = email; 1597 } 1598 if (e.isEmpty()) { 1599 return QString(); 1600 } 1601 1602 QString text; 1603 if (realName().isEmpty()) { 1604 text = e; 1605 } else { 1606 QRegularExpression needQuotes(QStringLiteral("[^ 0-9A-Za-z\\x{0080}-\\x{FFFF}]")); 1607 if (realName().indexOf(needQuotes) != -1) { 1608 QString name = realName(); 1609 name.replace(QLatin1String("\""), QLatin1String("\\\"")); 1610 text = QLatin1String("\"") + name + QLatin1String("\" <") + e + QLatin1Char('>'); 1611 } else { 1612 text = realName() + QLatin1String(" <") + e + QLatin1Char('>'); 1613 } 1614 } 1615 1616 return text; 1617 } 1618 1619 void Addressee::addEmail(const Email &email) 1620 { 1621 const QString mailAddr = email.mail(); 1622 auto it = std::find_if(d->mEmails.begin(), d->mEmails.end(), [&mailAddr](const Email &e) { 1623 return e.mail() == mailAddr; 1624 }); 1625 if (it != d->mEmails.end()) { // Already exists, modify it 1626 *it = email; 1627 if (email.isPreferred()) { 1628 // Move it to the beginning of mEmails 1629 std::rotate(d->mEmails.begin(), it, it + 1); 1630 } 1631 return; 1632 } 1633 1634 // Add it to the list 1635 d->mEmpty = false; 1636 if (email.isPreferred()) { 1637 d->mEmails.prepend(email); 1638 } else { 1639 d->mEmails.append(email); 1640 } 1641 } 1642 1643 #if KCONTACTS_BUILD_DEPRECATED_SINCE(5, 88) 1644 void Addressee::insertEmail(const QString &email, bool preferred, const QMap<QString, QStringList> ¶m) 1645 { 1646 if (email.simplified().isEmpty()) { 1647 return; 1648 } 1649 1650 for (int i = 0; i < d->mEmails.size(); ++i) { 1651 if (d->mEmails.at(i).mail() == email) { 1652 if (!preferred || i == 0) { 1653 return; 1654 } 1655 Email tempMail = d->mEmails.takeAt(i); 1656 d->mEmails.prepend(tempMail); 1657 return; 1658 } 1659 } 1660 1661 Email mail(email); 1662 mail.setParameters(param); 1663 d->mEmpty = false; 1664 if (preferred) { 1665 d->mEmails.prepend(mail); 1666 } else { 1667 d->mEmails.append(mail); 1668 } 1669 } 1670 #endif 1671 1672 void Addressee::removeEmail(const QString &email) 1673 { 1674 for (int i = 0; i < d->mEmails.size(); ++i) { 1675 if (d->mEmails.at(i).mail() == email) { 1676 d->mEmails.removeAt(i); 1677 } 1678 } 1679 } 1680 1681 QString Addressee::preferredEmail() const 1682 { 1683 if (d->mEmails.isEmpty()) { 1684 return QString(); 1685 } else { 1686 return d->mEmails.first().mail(); 1687 } 1688 } 1689 1690 QStringList Addressee::emails() const 1691 { 1692 QStringList list; 1693 const int numberOfEmail = d->mEmails.size(); 1694 list.reserve(numberOfEmail); 1695 for (int i = 0; i < numberOfEmail; ++i) { 1696 list << d->mEmails.at(i).mail(); 1697 } 1698 1699 return list; 1700 } 1701 1702 Email::List Addressee::emailList() const 1703 { 1704 return d->mEmails; 1705 } 1706 1707 void Addressee::setEmails(const QStringList &emails) 1708 { 1709 d->mEmails.clear(); 1710 const int numEmails = emails.size(); 1711 d->mEmails.reserve(numEmails); 1712 for (int i = 0; i < numEmails; ++i) { 1713 d->mEmails.append(Email(emails.at(i))); 1714 } 1715 d->mEmpty = false; 1716 } 1717 1718 void Addressee::setEmailList(const Email::List &list) 1719 { 1720 d->mEmails = list; 1721 d->mEmpty = false; 1722 } 1723 1724 void Addressee::removeLang(const QString &language) 1725 { 1726 for (int i = 0; i < d->mLangs.size(); ++i) { 1727 if (d->mLangs.at(i).language() == language) { 1728 d->mLangs.removeAt(i); 1729 } 1730 } 1731 } 1732 1733 void Addressee::setLangs(const Lang::List &langs) 1734 { 1735 d->mLangs = langs; 1736 d->mEmpty = false; 1737 } 1738 1739 void Addressee::insertLang(const Lang &language) 1740 { 1741 const QString languageStr = language.language(); 1742 if (languageStr.simplified().isEmpty()) { 1743 return; 1744 } 1745 d->mEmpty = false; 1746 1747 auto it = std::find_if(d->mLangs.begin(), d->mLangs.end(), [&languageStr](const Lang &lang) { 1748 return lang.language() == languageStr; 1749 }); 1750 if (it != d->mLangs.end()) { 1751 (*it).setParams(language.params()); 1752 return; 1753 } 1754 1755 d->mLangs.append(language); 1756 } 1757 1758 Lang::List Addressee::langs() const 1759 { 1760 return d->mLangs; 1761 } 1762 1763 void Addressee::setGender(const Gender &gender) 1764 { 1765 if (gender == d->mGender) { 1766 return; 1767 } 1768 1769 d->mEmpty = false; 1770 d->mGender = gender; 1771 } 1772 1773 Gender Addressee::gender() const 1774 { 1775 return d->mGender; 1776 } 1777 1778 void Addressee::insertPhoneNumber(const PhoneNumber &phoneNumber) 1779 { 1780 d->mEmpty = false; 1781 1782 auto it = std::find_if(d->mPhoneNumbers.begin(), d->mPhoneNumbers.end(), [&phoneNumber](const PhoneNumber &pNumber) { 1783 return pNumber.id() == phoneNumber.id(); 1784 }); 1785 if (it != d->mPhoneNumbers.end()) { 1786 *it = phoneNumber; 1787 return; 1788 } 1789 1790 if (!phoneNumber.number().simplified().isEmpty()) { 1791 d->mPhoneNumbers.append(phoneNumber); 1792 } 1793 } 1794 1795 void Addressee::removePhoneNumber(const PhoneNumber &phoneNumber) 1796 { 1797 auto it = std::find_if(d->mPhoneNumbers.begin(), d->mPhoneNumbers.end(), [&phoneNumber](const PhoneNumber &p) { 1798 return p.id() == phoneNumber.id(); 1799 }); 1800 1801 if (it != d->mPhoneNumbers.end()) { 1802 d->mPhoneNumbers.erase(it); 1803 } 1804 } 1805 1806 PhoneNumber Addressee::phoneNumber(PhoneNumber::Type type) const 1807 { 1808 PhoneNumber phoneNumber(QString(), type); 1809 1810 for (const PhoneNumber &phone : d->mPhoneNumbers) { 1811 if (matchBinaryPattern(phone.type(), type)) { 1812 if (phone.type() & PhoneNumber::Pref) { 1813 return phone; 1814 } else if (phoneNumber.number().isEmpty()) { 1815 phoneNumber = phone; 1816 } 1817 } 1818 } 1819 1820 return phoneNumber; 1821 } 1822 1823 PhoneNumber::List Addressee::phoneNumbers() const 1824 { 1825 return d->mPhoneNumbers; 1826 } 1827 1828 void Addressee::setPhoneNumbers(const PhoneNumber::List &phoneNumbers) 1829 { 1830 d->mEmpty = false; 1831 d->mPhoneNumbers.clear(); 1832 d->mPhoneNumbers = phoneNumbers; 1833 } 1834 1835 PhoneNumber::List Addressee::phoneNumbers(PhoneNumber::Type type) const 1836 { 1837 PhoneNumber::List list; 1838 1839 std::copy_if(d->mPhoneNumbers.cbegin(), d->mPhoneNumbers.cend(), std::back_inserter(list), [type](const auto &phone) { 1840 return matchBinaryPattern(phone.type(), type); 1841 }); 1842 return list; 1843 } 1844 1845 PhoneNumber Addressee::findPhoneNumber(const QString &id) const 1846 { 1847 auto it = std::find_if(d->mPhoneNumbers.cbegin(), d->mPhoneNumbers.cend(), [&id](const PhoneNumber &phone) { 1848 return phone.id() == id; 1849 }); 1850 1851 return it != d->mPhoneNumbers.cend() ? *it : PhoneNumber{}; 1852 } 1853 1854 void Addressee::insertKey(const Key &key) 1855 { 1856 d->mEmpty = false; 1857 1858 auto it = std::find_if(d->mKeys.begin(), d->mKeys.end(), [&key](Key &existing) { 1859 return existing.id() == key.id(); 1860 }); 1861 if (it != d->mKeys.end()) { 1862 *it = key; 1863 } else { 1864 d->mKeys.append(key); 1865 } 1866 } 1867 1868 void Addressee::removeKey(const Key &key) 1869 { 1870 auto it = std::remove_if(d->mKeys.begin(), d->mKeys.end(), [&key](const Key &k) { 1871 return k.id() == key.id(); 1872 }); 1873 d->mKeys.erase(it, d->mKeys.end()); 1874 } 1875 1876 Key Addressee::key(Key::Type type, const QString &customTypeString) const 1877 { 1878 for (const auto &key : d->mKeys) { 1879 if (key.type() == type) { 1880 if (type == Key::Custom) { 1881 if (customTypeString.isEmpty()) { 1882 return key; 1883 } else { 1884 if (key.customTypeString() == customTypeString) { 1885 return key; 1886 } 1887 } 1888 } else { 1889 return key; 1890 } 1891 } 1892 } 1893 return Key(QString(), type); 1894 } 1895 1896 void Addressee::setKeys(const Key::List &list) 1897 { 1898 d->mKeys = list; 1899 d->mEmpty = false; 1900 } 1901 1902 Key::List Addressee::keys() const 1903 { 1904 return d->mKeys; 1905 } 1906 1907 Key::List Addressee::keys(Key::Type type, const QString &customTypeString) const 1908 { 1909 Key::List list; 1910 auto matchFunc = [type, &customTypeString](const Key &key) { 1911 if (key.type() == type) { 1912 if (type == Key::Custom) { 1913 if (customTypeString.isEmpty()) { 1914 return true; 1915 } else { 1916 if (key.customTypeString() == customTypeString) { 1917 return true; 1918 } 1919 } 1920 } else { 1921 return true; 1922 } 1923 } 1924 return false; 1925 }; 1926 1927 std::copy_if(d->mKeys.cbegin(), d->mKeys.cend(), std::back_inserter(list), matchFunc); 1928 1929 return list; 1930 } 1931 1932 Key Addressee::findKey(const QString &id) const 1933 { 1934 auto it = std::find_if(d->mKeys.cbegin(), d->mKeys.cend(), [&id](const Key &key) { 1935 return key.id() == id; 1936 }); 1937 1938 return it != d->mKeys.cend() ? *it : Key{}; 1939 } 1940 1941 QString Addressee::toString() const 1942 { 1943 QString str = QLatin1String("Addressee {\n"); 1944 str += QStringLiteral(" Uid: %1\n").arg(uid()); 1945 1946 str += QStringLiteral(" Name: %1\n").arg(name()); 1947 str += QStringLiteral(" FormattedName: %1\n").arg(formattedName()); 1948 str += QStringLiteral(" FamilyName: %1\n").arg(familyName()); 1949 str += QStringLiteral(" GivenName: %1\n").arg(givenName()); 1950 str += QStringLiteral(" AdditionalName: %1\n").arg(additionalName()); 1951 str += QStringLiteral(" Prefix: %1\n").arg(prefix()); 1952 str += QStringLiteral(" Suffix: %1\n").arg(suffix()); 1953 str += QStringLiteral(" NickName: %1\n").arg(nickName()); 1954 str += QStringLiteral(" Birthday: %1\n").arg(birthday().toString()); 1955 str += QStringLiteral(" Mailer: %1\n").arg(mailer()); 1956 str += QStringLiteral(" TimeZone: %1\n").arg(timeZone().toString()); 1957 str += QStringLiteral(" Geo: %1\n").arg(geo().toString()); 1958 str += QStringLiteral(" Title: %1\n").arg(title()); 1959 str += QStringLiteral(" Role: %1\n").arg(role()); 1960 str += QStringLiteral(" Organization: %1\n").arg(organization()); 1961 str += QStringLiteral(" Department: %1\n").arg(department()); 1962 str += QStringLiteral(" Note: %1\n").arg(note()); 1963 str += QStringLiteral(" ProductId: %1\n").arg(productId()); 1964 str += QStringLiteral(" Revision: %1\n").arg(revision().toString()); 1965 str += QStringLiteral(" SortString: %1\n").arg(sortString()); 1966 str += QStringLiteral(" Url: %1\n").arg(url().url().url()); 1967 str += QStringLiteral(" Secrecy: %1\n").arg(secrecy().toString()); 1968 str += QStringLiteral(" Logo: %1\n").arg(logo().toString()); 1969 str += QStringLiteral(" Photo: %1\n").arg(photo().toString()); 1970 str += QStringLiteral(" Sound: %1\n").arg(sound().toString()); 1971 str += QStringLiteral(" Gender: %1\n").arg(gender().toString()); 1972 str += QStringLiteral(" Kind: %1\n").arg(kind()); 1973 1974 str += QLatin1String(" Emails {\n"); 1975 const Email::List listEmail = d->mEmails; 1976 for (const Email &email : listEmail) { 1977 str += email.toString(); 1978 } 1979 str += QLatin1String(" }\n"); 1980 1981 str += QLatin1String(" Langs {\n"); 1982 const Lang::List listLang = d->mLangs; 1983 for (const Lang &lang : listLang) { 1984 str += lang.toString(); 1985 } 1986 str += QLatin1String(" }\n"); 1987 1988 str += QLatin1String(" PhoneNumbers {\n"); 1989 const PhoneNumber::List phones = phoneNumbers(); 1990 for (const auto &p : phones) { 1991 str += p.toString(); 1992 } 1993 str += QLatin1String(" }\n"); 1994 1995 str += QLatin1String(" Addresses {\n"); 1996 const Address::List addrList = addresses(); 1997 for (const auto &addr : addrList) { 1998 str += addr.toString(); 1999 } 2000 str += QLatin1String(" }\n"); 2001 2002 str += QLatin1String(" Keys {\n"); 2003 const Key::List keyList = keys(); 2004 for (const auto &k : keyList) { 2005 str += k.toString(); 2006 } 2007 str += QLatin1String(" }\n"); 2008 2009 str += QLatin1String("}\n"); 2010 2011 return str; 2012 } 2013 2014 void Addressee::insertAddress(const Address &address) 2015 { 2016 if (address.isEmpty()) { 2017 return; 2018 } 2019 2020 d->mEmpty = false; 2021 2022 auto it = std::find_if(d->mAddresses.begin(), d->mAddresses.end(), [&address](const Address &addr) { 2023 return addr.id() == address.id(); 2024 }); 2025 if (it != d->mAddresses.end()) { 2026 *it = address; 2027 return; 2028 } 2029 2030 d->mAddresses.append(address); 2031 } 2032 2033 void Addressee::removeAddress(const Address &address) 2034 { 2035 auto it = std::find_if(d->mAddresses.begin(), d->mAddresses.end(), [&address](const Address &addr) { 2036 return addr.id() == address.id(); 2037 }); 2038 if (it != d->mAddresses.end()) { 2039 d->mAddresses.erase(it); 2040 } 2041 } 2042 2043 void Addressee::setAddresses(const Address::List &addresses) 2044 { 2045 d->mEmpty = false; 2046 d->mAddresses = addresses; 2047 } 2048 2049 Address Addressee::address(Address::Type type) const 2050 { 2051 Address address(type); 2052 for (const Address &addr : d->mAddresses) { 2053 if (matchBinaryPattern(addr.type(), type)) { 2054 if (addr.type() & Address::Pref) { 2055 return addr; 2056 } else if (address.isEmpty()) { 2057 address = addr; 2058 } 2059 } 2060 } 2061 2062 return address; 2063 } 2064 2065 Address::List Addressee::addresses() const 2066 { 2067 return d->mAddresses; 2068 } 2069 2070 Address::List Addressee::addresses(Address::Type type) const 2071 { 2072 Address::List list; 2073 2074 std::copy_if(d->mAddresses.cbegin(), d->mAddresses.cend(), std::back_inserter(list), [type](const Address &addr) { 2075 return matchBinaryPattern(addr.type(), type); 2076 }); 2077 2078 return list; 2079 } 2080 2081 Address Addressee::findAddress(const QString &id) const 2082 { 2083 auto it = std::find_if(d->mAddresses.cbegin(), d->mAddresses.cend(), [&id](const Address &addr) { 2084 return addr.id() == id; 2085 }); 2086 return it != d->mAddresses.cend() ? *it : Address{}; 2087 } 2088 2089 void Addressee::insertCategory(const QString &c) 2090 { 2091 d->mEmpty = false; 2092 2093 if (d->mCategories.contains(c)) { 2094 return; 2095 } 2096 2097 d->mCategories.append(c); 2098 } 2099 2100 void Addressee::removeCategory(const QString &category) 2101 { 2102 if (d->mCategories.contains(category)) { 2103 d->mCategories.removeAll(category); 2104 } 2105 } 2106 2107 bool Addressee::hasCategory(const QString &category) const 2108 { 2109 return d->mCategories.contains(category); 2110 } 2111 2112 void Addressee::setCategories(const QStringList &c) 2113 { 2114 d->mEmpty = false; 2115 2116 d->mCategories = c; 2117 } 2118 2119 QStringList Addressee::categories() const 2120 { 2121 return d->mCategories; 2122 } 2123 2124 void Addressee::insertMember(const QString &member) 2125 { 2126 d->mEmpty = false; 2127 2128 if (d->mMembers.contains(member)) { 2129 return; 2130 } 2131 2132 d->mMembers.append(member); 2133 } 2134 2135 void Addressee::setMembers(const QStringList &m) 2136 { 2137 d->mEmpty = false; 2138 d->mMembers = m; 2139 } 2140 2141 QStringList Addressee::members() const 2142 { 2143 return d->mMembers; 2144 } 2145 2146 void Addressee::insertRelationship(const Related &relation) 2147 { 2148 d->mEmpty = false; 2149 2150 if (d->mRelationships.contains(relation)) { 2151 return; 2152 } 2153 2154 d->mRelationships.append(relation); 2155 } 2156 2157 void Addressee::setRelationships(const Related::List &c) 2158 { 2159 d->mEmpty = false; 2160 d->mRelationships = c; 2161 } 2162 2163 Related::List Addressee::relationships() const 2164 { 2165 return d->mRelationships; 2166 } 2167 2168 static const auto VENDOR_ID = QStringLiteral("KADDRESSBOOK"); 2169 static const auto X_ANNIVERSARY = QStringLiteral("X-Anniversary"); 2170 static const auto X_ASSISTANTSNAME = QStringLiteral("X-AssistantsName"); 2171 static const auto BLOGFEED = QStringLiteral("BlogFeed"); 2172 static const auto X_MANAGERSNAME = QStringLiteral("X-ManagersName"); 2173 static const auto X_OFFICE = QStringLiteral("X-Office"); 2174 static const auto X_PROFESSION = QStringLiteral("X-Profession"); 2175 static const auto X_SPOUSESNAME = QStringLiteral("X-SpousesName"); 2176 2177 QDate Addressee::anniversary() const 2178 { 2179 return QDate::fromString(custom(VENDOR_ID, X_ANNIVERSARY), Qt::ISODate); 2180 } 2181 2182 void Addressee::setAnniversary(const QDate &anniversary) 2183 { 2184 if (anniversary.isValid()) { 2185 insertCustom(VENDOR_ID, X_ANNIVERSARY, anniversary.toString(Qt::ISODate)); 2186 } else { 2187 removeCustom(VENDOR_ID, X_ANNIVERSARY); 2188 } 2189 } 2190 2191 QString Addressee::assistantsName() const 2192 { 2193 return custom(VENDOR_ID, X_ASSISTANTSNAME); 2194 } 2195 2196 void Addressee::setAssistantsName(const QString &assistantsName) 2197 { 2198 if (!assistantsName.isEmpty()) { 2199 insertCustom(VENDOR_ID, X_ASSISTANTSNAME, assistantsName); 2200 } else { 2201 removeCustom(VENDOR_ID, X_ASSISTANTSNAME); 2202 } 2203 } 2204 2205 QUrl Addressee::blogFeed() const 2206 { 2207 return QUrl(custom(VENDOR_ID, BLOGFEED)); 2208 } 2209 2210 void Addressee::setBlogFeed(const QUrl &blogFeed) 2211 { 2212 if (!blogFeed.isEmpty()) { 2213 insertCustom(VENDOR_ID, BLOGFEED, blogFeed.url()); 2214 } else { 2215 removeCustom(VENDOR_ID, BLOGFEED); 2216 } 2217 } 2218 2219 QString Addressee::managersName() const 2220 { 2221 return custom(VENDOR_ID, X_MANAGERSNAME); 2222 } 2223 2224 void Addressee::setManagersName(const QString &managersName) 2225 { 2226 if (!managersName.isEmpty()) { 2227 insertCustom(VENDOR_ID, X_MANAGERSNAME, managersName); 2228 } else { 2229 removeCustom(VENDOR_ID, X_MANAGERSNAME); 2230 } 2231 } 2232 2233 QString Addressee::office() const 2234 { 2235 return custom(VENDOR_ID, X_OFFICE); 2236 } 2237 2238 void Addressee::setOffice(const QString &office) 2239 { 2240 if (!office.isEmpty()) { 2241 insertCustom(VENDOR_ID, X_OFFICE, office); 2242 } else { 2243 removeCustom(VENDOR_ID, X_OFFICE); 2244 } 2245 } 2246 2247 QString Addressee::profession() const 2248 { 2249 return custom(VENDOR_ID, X_PROFESSION); 2250 } 2251 2252 void Addressee::setProfession(const QString &profession) 2253 { 2254 if (!profession.isEmpty()) { 2255 insertCustom(VENDOR_ID, X_PROFESSION, profession); 2256 } else { 2257 removeCustom(VENDOR_ID, X_PROFESSION); 2258 } 2259 } 2260 2261 QString Addressee::spousesName() const 2262 { 2263 return custom(VENDOR_ID, X_SPOUSESNAME); 2264 } 2265 2266 void Addressee::setSpousesName(const QString &spousesName) 2267 { 2268 if (!spousesName.isEmpty()) { 2269 insertCustom(VENDOR_ID, X_SPOUSESNAME, spousesName); 2270 } else { 2271 removeCustom(VENDOR_ID, X_SPOUSESNAME); 2272 } 2273 } 2274 2275 void Addressee::insertCustom(const QString &app, const QString &name, const QString &value) 2276 { 2277 if (value.isEmpty() || name.isEmpty() || app.isEmpty()) { 2278 return; 2279 } 2280 2281 d->mEmpty = false; 2282 2283 const QString qualifiedName = app + QLatin1Char('-') + name; 2284 2285 auto it = d->findByName(qualifiedName); 2286 if (it != d->mCustomFields.end()) { 2287 it->value = value; 2288 } else { 2289 const CustomData newdata{qualifiedName, value}; 2290 auto beforeIt = std::lower_bound(d->mCustomFields.begin(), d->mCustomFields.end(), newdata); 2291 d->mCustomFields.insert(beforeIt, newdata); 2292 } 2293 } 2294 2295 void Addressee::removeCustom(const QString &app, const QString &name) 2296 { 2297 const QString qualifiedName = app + QLatin1Char('-') + name; 2298 auto it = d->findByName(qualifiedName); 2299 if (it != d->mCustomFields.end()) { 2300 d->mCustomFields.erase(it); 2301 } 2302 } 2303 2304 QString Addressee::custom(const QString &app, const QString &name) const 2305 { 2306 const QString qualifiedName = app + QLatin1Char('-') + name; 2307 auto it = d->findByName(qualifiedName); 2308 return it != d->mCustomFields.cend() ? it->value : QString{}; 2309 } 2310 2311 void Addressee::setCustoms(const QStringList &customs) 2312 { 2313 d->mEmpty = false; 2314 2315 d->mCustomFields.clear(); 2316 2317 // Less than 10 elements in "customs", we needn't use a set 2318 QStringList seen; 2319 for (const QString &custom : customs) { 2320 const int index = custom.indexOf(QLatin1Char(':')); 2321 if (index == -1) { 2322 continue; 2323 } 2324 2325 const QString qualifiedName = custom.left(index); 2326 const QString value = custom.mid(index + 1); 2327 2328 if (!seen.contains(qualifiedName)) { 2329 d->mCustomFields.push_back({qualifiedName, value}); 2330 seen.push_back(qualifiedName); 2331 } 2332 } 2333 std::sort(d->mCustomFields.begin(), d->mCustomFields.end()); 2334 } 2335 2336 QStringList Addressee::customs() const 2337 { 2338 QStringList result; 2339 result.reserve(d->mCustomFields.size()); 2340 2341 static const QLatin1Char sep(':'); 2342 for (const auto &[name, value] : d->mCustomFields) { 2343 result << name + sep + value; 2344 } 2345 2346 return result; 2347 } 2348 2349 void Addressee::parseEmailAddress(const QString &rawEmail, QString &fullName, QString &email) 2350 { 2351 // This is a simplified version of KPIM::splitAddress(). 2352 2353 fullName.clear(); 2354 email.clear(); 2355 if (rawEmail.isEmpty()) { 2356 return; // KPIM::AddressEmpty; 2357 } 2358 2359 // The code works on 8-bit strings, so convert the input to UTF-8. 2360 QByteArray address = rawEmail.toUtf8(); 2361 2362 QByteArray displayName; 2363 QByteArray addrSpec; 2364 QByteArray comment; 2365 2366 // The following is a primitive parser for a mailbox-list (cf. RFC 2822). 2367 // The purpose is to extract a displayable string from the mailboxes. 2368 // Comments in the addr-spec are not handled. No error checking is done. 2369 2370 enum sourceLevel { 2371 TopLevel, 2372 InComment, 2373 InAngleAddress, 2374 }; 2375 sourceLevel context = TopLevel; 2376 bool inQuotedString = false; 2377 int commentLevel = 0; 2378 bool stop = false; 2379 2380 for (char *p = address.data(); *p && !stop; ++p) { 2381 switch (context) { 2382 case TopLevel: 2383 switch (*p) { 2384 case '"': 2385 inQuotedString = !inQuotedString; 2386 displayName += *p; 2387 break; 2388 case '(': 2389 if (!inQuotedString) { 2390 context = InComment; 2391 commentLevel = 1; 2392 } else { 2393 displayName += *p; 2394 } 2395 break; 2396 case '<': 2397 if (!inQuotedString) { 2398 context = InAngleAddress; 2399 } else { 2400 displayName += *p; 2401 } 2402 break; 2403 case '\\': // quoted character 2404 displayName += *p; 2405 ++p; // skip the '\' 2406 if (*p) { 2407 displayName += *p; 2408 } else { 2409 // return KPIM::UnexpectedEnd; 2410 goto ABORT_PARSING; 2411 } 2412 break; 2413 case ',': 2414 if (!inQuotedString) { 2415 // if ( allowMultipleAddresses ) 2416 // stop = true; 2417 // else 2418 // return KPIM::UnexpectedComma; 2419 goto ABORT_PARSING; 2420 } else { 2421 displayName += *p; 2422 } 2423 break; 2424 default: 2425 displayName += *p; 2426 } 2427 break; 2428 case InComment: 2429 switch (*p) { 2430 case '(': 2431 ++commentLevel; 2432 comment += *p; 2433 break; 2434 case ')': 2435 --commentLevel; 2436 if (commentLevel == 0) { 2437 context = TopLevel; 2438 comment += ' '; // separate the text of several comments 2439 } else { 2440 comment += *p; 2441 } 2442 break; 2443 case '\\': // quoted character 2444 comment += *p; 2445 ++p; // skip the '\' 2446 if (*p) { 2447 comment += *p; 2448 } else { 2449 // return KPIM::UnexpectedEnd; 2450 goto ABORT_PARSING; 2451 } 2452 break; 2453 default: 2454 comment += *p; 2455 } 2456 break; 2457 case InAngleAddress: 2458 switch (*p) { 2459 case '"': 2460 inQuotedString = !inQuotedString; 2461 addrSpec += *p; 2462 break; 2463 case '>': 2464 if (!inQuotedString) { 2465 context = TopLevel; 2466 } else { 2467 addrSpec += *p; 2468 } 2469 break; 2470 case '\\': // quoted character 2471 addrSpec += *p; 2472 ++p; // skip the '\' 2473 if (*p) { 2474 addrSpec += *p; 2475 } else { 2476 // return KPIM::UnexpectedEnd; 2477 goto ABORT_PARSING; 2478 } 2479 break; 2480 default: 2481 addrSpec += *p; 2482 } 2483 break; 2484 } // switch ( context ) 2485 } 2486 2487 ABORT_PARSING: 2488 displayName = displayName.trimmed(); 2489 comment = comment.trimmed(); 2490 addrSpec = addrSpec.trimmed(); 2491 fullName = QString::fromUtf8(displayName); 2492 email = QString::fromUtf8(addrSpec); // check for errors 2493 if (inQuotedString) { 2494 return; // KPIM::UnbalancedQuote; 2495 } 2496 if (context == InComment) { 2497 return; // KPIM::UnbalancedParens; 2498 } 2499 if (context == InAngleAddress) { 2500 return; // KPIM::UnclosedAngleAddr; 2501 } 2502 2503 if (addrSpec.isEmpty()) { 2504 if (displayName.isEmpty()) { 2505 return; // KPIM::NoAddressSpec; 2506 } else { 2507 // addrSpec = displayName; 2508 // displayName.truncate( 0 ); 2509 // Address of the form "foo@bar" or "foo@bar (Name)". 2510 email = fullName; 2511 fullName = QString::fromUtf8(comment); 2512 } 2513 } 2514 2515 email = email.toLower(); 2516 2517 // Check that the full name is not enclosed in balanced double quotes. 2518 // If it is then remove them. 2519 const unsigned int len = fullName.length(); 2520 if (len < 3) { // not long enough to be 2521 return; 2522 } 2523 if (fullName.startsWith(QLatin1Char('"')) && fullName.endsWith(QLatin1Char('"'))) { 2524 fullName = fullName.mid(1, len - 2); 2525 } 2526 } 2527 2528 void Addressee::setChanged(bool value) 2529 { 2530 d->mChanged = value; 2531 } 2532 2533 bool Addressee::changed() const 2534 { 2535 return d->mChanged; 2536 } 2537 2538 QString Addressee::mimeType() 2539 { 2540 return QStringLiteral("text/directory"); 2541 } 2542 2543 QDataStream &KContacts::operator<<(QDataStream &s, const Addressee &a) 2544 { 2545 s << a.d->mUid; 2546 2547 s << a.d->mName; 2548 s << a.d->mFormattedName; 2549 s << a.d->mFamilyName; 2550 s << a.d->mGivenName; 2551 s << a.d->mAdditionalName; 2552 s << a.d->mPrefix; 2553 s << a.d->mSuffix; 2554 s << a.d->mBirthday; 2555 s << a.d->mBirthdayWithTime; 2556 s << a.d->mMailer; 2557 s << a.d->mTimeZone; 2558 s << a.d->mGeo; 2559 s << a.d->mDepartment; 2560 s << a.d->mNote; 2561 s << a.d->mProductId; 2562 s << a.d->mRevision; 2563 s << a.d->mSortString; 2564 s << a.d->mSecrecy; 2565 s << a.d->mLogo; 2566 s << a.d->mPhoto; 2567 s << a.d->mSound; 2568 s << a.d->mPhoneNumbers; 2569 s << a.d->mAddresses; 2570 s << a.d->mEmails; 2571 s << a.d->mCategories; 2572 s << a.customs(); 2573 s << a.d->mKeys; 2574 s << a.d->mLangs; 2575 s << a.d->mGender; 2576 s << a.d->mKind; 2577 s << a.d->mCalendarUrl; 2578 s << a.d->mSoundListExtra; 2579 s << a.d->mPhotoExtraList; 2580 s << a.d->mLogoExtraList; 2581 s << a.d->mUrlExtraList; 2582 s << a.d->mMembers; 2583 s << a.d->mRelationships; 2584 s << a.d->mSources; 2585 s << a.d->mImpps; 2586 s << a.d->mFieldGroupList; 2587 s << a.d->mTitleExtraList; 2588 s << a.d->mRoleExtraList; 2589 s << a.d->mOrgExtraList; 2590 s << a.d->mNickNameExtraList; 2591 s << a.d->mClientPidMapList; 2592 2593 return s; 2594 } 2595 2596 QDataStream &KContacts::operator>>(QDataStream &s, Addressee &a) 2597 { 2598 s >> a.d->mUid; 2599 2600 s >> a.d->mName; 2601 s >> a.d->mFormattedName; 2602 s >> a.d->mFamilyName; 2603 s >> a.d->mGivenName; 2604 s >> a.d->mAdditionalName; 2605 s >> a.d->mPrefix; 2606 s >> a.d->mSuffix; 2607 s >> a.d->mBirthday; 2608 s >> a.d->mBirthdayWithTime; 2609 s >> a.d->mMailer; 2610 s >> a.d->mTimeZone; 2611 s >> a.d->mGeo; 2612 s >> a.d->mDepartment; 2613 s >> a.d->mNote; 2614 s >> a.d->mProductId; 2615 s >> a.d->mRevision; 2616 s >> a.d->mSortString; 2617 s >> a.d->mSecrecy; 2618 s >> a.d->mLogo; 2619 s >> a.d->mPhoto; 2620 s >> a.d->mSound; 2621 s >> a.d->mPhoneNumbers; 2622 s >> a.d->mAddresses; 2623 s >> a.d->mEmails; 2624 s >> a.d->mCategories; 2625 QStringList customFields; 2626 s >> customFields; 2627 a.setCustoms(customFields); 2628 s >> a.d->mKeys; 2629 s >> a.d->mLangs; 2630 s >> a.d->mGender; 2631 s >> a.d->mKind; 2632 s >> a.d->mCalendarUrl; 2633 s >> a.d->mSoundListExtra; 2634 s >> a.d->mPhotoExtraList; 2635 s >> a.d->mLogoExtraList; 2636 s >> a.d->mUrlExtraList; 2637 s >> a.d->mMembers; 2638 s >> a.d->mRelationships; 2639 s >> a.d->mSources; 2640 s >> a.d->mImpps; 2641 s >> a.d->mFieldGroupList; 2642 s >> a.d->mTitleExtraList; 2643 s >> a.d->mRoleExtraList; 2644 s >> a.d->mOrgExtraList; 2645 s >> a.d->mNickNameExtraList; 2646 s >> a.d->mClientPidMapList; 2647 a.d->mEmpty = false; 2648 2649 return s; 2650 } 2651 2652 bool matchBinaryPattern(int value, int pattern) 2653 { 2654 /** 2655 We want to match all telephonnumbers/addresses which have the bits in the 2656 pattern set. More are allowed. 2657 if pattern == 0 we have a special handling, then we want only those with 2658 exactly no bit set. 2659 */ 2660 if (pattern == 0) { 2661 return value == 0; 2662 } else { 2663 return pattern == (pattern & value); 2664 } 2665 } 2666 2667 template<class L> 2668 bool listEquals(const QVector<L> &list, const QVector<L> &pattern) 2669 { 2670 if (list.count() != pattern.count()) { 2671 return false; 2672 } 2673 const int numberOfElement(list.count()); 2674 for (int i = 0; i < numberOfElement; ++i) { 2675 if (!pattern.contains(list[i])) { 2676 return false; 2677 } 2678 } 2679 2680 return true; 2681 } 2682 2683 bool listEquals(const QStringList &list, const QStringList &pattern) 2684 { 2685 if (list.count() != pattern.count()) { 2686 return false; 2687 } 2688 2689 const int numberOfElement(list.count()); 2690 for (int i = 0; i < numberOfElement; ++i) { 2691 if (!pattern.contains(list[i])) { 2692 return false; 2693 } 2694 } 2695 2696 return true; 2697 } 2698 2699 template<typename T> 2700 static QVariantList toVariantList(const QVector<T> &v) 2701 { 2702 QVariantList l; 2703 l.reserve(v.size()); 2704 std::transform(v.begin(), v.end(), std::back_inserter(l), [](const T &elem) { 2705 return QVariant::fromValue(elem); 2706 }); 2707 return l; 2708 } 2709 2710 template<typename T> 2711 static QVector<T> fromVariantList(const QVariantList &v) 2712 { 2713 QVector<T> l; 2714 l.reserve(v.size()); 2715 std::transform(v.begin(), v.end(), std::back_inserter(l), [](const QVariant &elem) { 2716 return elem.value<T>(); 2717 }); 2718 return l; 2719 } 2720 2721 void Addressee::setBirthdayProperty(const QDateTime &birthday) { 2722 // The property setter cannot pass withTime, so we have to guess. 2723 setBirthday(birthday, birthday.time().msecsSinceStartOfDay() != 0); 2724 } 2725 2726 QVariantList Addressee::emailsVariant() const 2727 { 2728 return toVariantList(d->mEmails); 2729 } 2730 2731 void Addressee::setEmailsVariant(const QVariantList &emails) 2732 { 2733 setEmailList(fromVariantList<Email>(emails)); 2734 } 2735 2736 void Addressee::setPhoneNumbersVariant(const QVariantList &emails) 2737 { 2738 setPhoneNumbers(fromVariantList<PhoneNumber>(emails)); 2739 } 2740 2741 QVariantList Addressee::phoneNumbersVariant() const 2742 { 2743 return toVariantList(d->mPhoneNumbers); 2744 } 2745 2746 QVariantList Addressee::addressesVariant() const 2747 { 2748 return toVariantList(d->mAddresses); 2749 } 2750 2751 QVariantList Addressee::urlsVariant() const 2752 { 2753 return toVariantList(d->mUrlExtraList); 2754 } 2755 2756 QVariantList Addressee::imppsVariant() const 2757 { 2758 return toVariantList(d->mImpps); 2759 } 2760 2761 void Addressee::setImppsVariant(const QVariantList &impps) 2762 { 2763 setImppList(fromVariantList<Impp>(impps)); 2764 } 2765 2766 #include "moc_addressee.cpp"