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