KContacts

addressee.cpp
1 /*
2  This file is part of the KContacts framework.
3  SPDX-FileCopyrightText: 2001 Cornelius Schumacher <[email protected]>
4  SPDX-FileCopyrightText: 2003 Carsten Pfeiffer <[email protected]>
5  SPDX-FileCopyrightText: 2005 Ingo Kloecker <[email protected]>
6 
7  SPDX-License-Identifier: LGPL-2.0-or-later
8 */
9 
10 #include <QDate>
11 #include <QRegularExpression>
12 #include <QSharedData>
13 #include <QUuid>
14 
15 #include "kcontacts_debug.h"
16 #include <KLocalizedString>
17 
18 #include "addressee.h"
19 #include "addresseehelper.h"
20 #include "field.h"
21 #include "parametermap_p.h"
22 
23 using namespace KContacts;
24 
25 static bool matchBinaryPattern(int value, int pattern);
26 
27 template<class L>
28 static bool listEquals(const QVector<L> &list, const QVector<L> &pattern);
29 static bool listEquals(const QStringList &list, const QStringList &pattern);
30 
31 struct CustomData {
32  QString name;
33  QString value;
34 };
35 
36 inline bool operator==(const CustomData &a, const CustomData &b)
37 {
38  return std::tie(a.name, a.value) == std::tie(b.name, b.value);
39 }
40 
41 inline bool operator!=(const CustomData &a, const CustomData &b)
42 {
43  return std::tie(a.name, a.value) != std::tie(b.name, b.value);
44 }
45 
46 inline bool operator<(const CustomData &a, const CustomData &b)
47 {
48  return a.name < b.name;
49 }
50 
51 class Q_DECL_HIDDEN Addressee::Private : public QSharedData
52 {
53 public:
54  Private()
55  : mUid(QUuid::createUuid().toString().mid(1, 36))
56  , mEmpty(true)
57  , mChanged(false)
58  , mBirthdayWithTime(false)
59  {
60  // We avoid the curly braces so the string is RFC4122 compliant and can be used as urn
61  }
62 
63  Private(const Private &other)
64  : QSharedData(other)
65  {
66  mUid = other.mUid;
67  mName = other.mName;
68  mFormattedName = other.mFormattedName;
69  mFamilyName = other.mFamilyName;
70  mGivenName = other.mGivenName;
71  mAdditionalName = other.mAdditionalName;
72  mPrefix = other.mPrefix;
73  mSuffix = other.mSuffix;
74  mBirthday = other.mBirthday;
75  mBirthdayWithTime = other.mBirthdayWithTime;
76  mMailer = other.mMailer;
77  mTimeZone = other.mTimeZone;
78  mGeo = other.mGeo;
79  mDepartment = other.mDepartment;
80  mNote = other.mNote;
81  mProductId = other.mProductId;
82  mRevision = other.mRevision;
83  mSortString = other.mSortString;
84  mSecrecy = other.mSecrecy;
85  mLogo = other.mLogo;
86  mPhoto = other.mPhoto;
87  mSound = other.mSound;
88 
89  mPhoneNumbers = other.mPhoneNumbers;
90  mAddresses = other.mAddresses;
91  mKeys = other.mKeys;
92  mLangs = other.mLangs;
93  mGender = other.mGender;
94  mEmails = other.mEmails;
95  mCategories = other.mCategories;
96  mCustomFields = other.mCustomFields;
97  mCalendarUrl = other.mCalendarUrl;
98  mSoundListExtra = other.mSoundListExtra;
99  mPhotoExtraList = other.mPhotoExtraList;
100  mLogoExtraList = other.mLogoExtraList;
101  mUrlExtraList = other.mUrlExtraList;
102  mMembers = other.mMembers;
103  mRelationships = other.mRelationships;
104  mSources = other.mSources;
105  mEmpty = other.mEmpty;
106  mImpps = other.mImpps;
107  mChanged = other.mChanged;
108  mTitleExtraList = other.mTitleExtraList;
109  mRoleExtraList = other.mRoleExtraList;
110  mOrgExtraList = other.mOrgExtraList;
111  }
112 
113  ~Private()
114  {
115  }
116 
117  std::vector<CustomData>::iterator findByName(const QString &qualifiedName)
118  {
119  return std::find_if(mCustomFields.begin(), mCustomFields.end(), [&qualifiedName](const CustomData &info) {
120  return info.name == qualifiedName;
121  });
122  }
123 
124  std::vector<CustomData>::const_iterator findByName(const QString &qualifiedName) const
125  {
126  return std::find_if(mCustomFields.cbegin(), mCustomFields.cend(), [&qualifiedName](const CustomData &info) {
127  return info.name == qualifiedName;
128  });
129  }
130 
131  QString mUid;
132  QString mName;
133  QString mFormattedName;
134  QString mFamilyName;
135  QString mGivenName;
136  QString mAdditionalName;
137  QString mPrefix;
138  QString mSuffix;
139  QDateTime mBirthday;
140  QString mMailer;
141  TimeZone mTimeZone;
142  Geo mGeo;
143  QString mDepartment;
144  QString mNote;
145  QString mProductId;
146  QDateTime mRevision;
147  QString mSortString;
148  Secrecy mSecrecy;
149  Picture mLogo;
150  Picture mPhoto;
151  Sound mSound;
152 
153  PhoneNumber::List mPhoneNumbers;
154  Address::List mAddresses;
155  Key::List mKeys;
156  Email::List mEmails;
157  Lang::List mLangs;
158  Impp::List mImpps;
159  Gender mGender;
160  QString mKind;
161  QStringList mCategories;
162  std::vector<CustomData> mCustomFields;
163  CalendarUrl::List mCalendarUrl;
164  Sound::List mSoundListExtra;
165  Picture::List mPhotoExtraList;
166  Picture::List mLogoExtraList;
167  ResourceLocatorUrl::List mUrlExtraList;
168  QVector<QUrl> mSources;
169  QStringList mMembers;
170  Related::List mRelationships;
171  FieldGroup::List mFieldGroupList;
172  Title::List mTitleExtraList;
173  Role::List mRoleExtraList;
174  Org::List mOrgExtraList;
175  NickName::List mNickNameExtraList;
176  ClientPidMap::List mClientPidMapList;
177  bool mEmpty : 1;
178  bool mChanged : 1;
179  bool mBirthdayWithTime;
180 };
181 
183  : d(new Private)
184 {
185 }
186 
188 {
189 }
190 
192  : d(other.d)
193 {
194 }
195 
197 {
198  if (this != &other) {
199  d = other.d;
200  }
201 
202  return *this;
203 }
204 
205 bool Addressee::operator==(const Addressee &addressee) const
206 {
207  if (d->mUid != addressee.d->mUid) {
208  qCDebug(KCONTACTS_LOG) << "uid differs";
209  return false;
210  }
211 
212  if (d->mName != addressee.d->mName //
213  && !(d->mName.isEmpty() && addressee.d->mName.isEmpty())) {
214  qCDebug(KCONTACTS_LOG) << "name differs";
215  return false;
216  }
217 
218  if (d->mFormattedName != addressee.d->mFormattedName //
219  && !(d->mFormattedName.isEmpty() && addressee.d->mFormattedName.isEmpty())) {
220  qCDebug(KCONTACTS_LOG) << "formattedName differs";
221  return false;
222  }
223 
224  if (d->mFamilyName != addressee.d->mFamilyName //
225  && !(d->mFamilyName.isEmpty() && addressee.d->mFamilyName.isEmpty())) {
226  qCDebug(KCONTACTS_LOG) << "familyName differs";
227  return false;
228  }
229 
230  if (d->mGivenName != addressee.d->mGivenName //
231  && !(d->mGivenName.isEmpty() && addressee.d->mGivenName.isEmpty())) {
232  qCDebug(KCONTACTS_LOG) << "givenName differs";
233  return false;
234  }
235 
236  if (d->mAdditionalName != addressee.d->mAdditionalName //
237  && !(d->mAdditionalName.isEmpty() && addressee.d->mAdditionalName.isEmpty())) {
238  qCDebug(KCONTACTS_LOG) << "additionalName differs";
239  return false;
240  }
241 
242  if (d->mPrefix != addressee.d->mPrefix //
243  && !(d->mPrefix.isEmpty() && addressee.d->mPrefix.isEmpty())) {
244  qCDebug(KCONTACTS_LOG) << "prefix differs";
245  return false;
246  }
247 
248  if (d->mSuffix != addressee.d->mSuffix //
249  && !(d->mSuffix.isEmpty() && addressee.d->mSuffix.isEmpty())) {
250  qCDebug(KCONTACTS_LOG) << "suffix differs";
251  return false;
252  }
253 
254  if (d->mBirthday != addressee.d->mBirthday //
255  || d->mBirthdayWithTime != addressee.d->mBirthdayWithTime) {
256  qCDebug(KCONTACTS_LOG) << "birthday differs";
257  return false;
258  }
259 
260  if (d->mMailer != addressee.d->mMailer //
261  && !(d->mMailer.isEmpty() && addressee.d->mMailer.isEmpty())) {
262  qCDebug(KCONTACTS_LOG) << "mailer differs";
263  return false;
264  }
265 
266  if (d->mTimeZone != addressee.d->mTimeZone) {
267  qCDebug(KCONTACTS_LOG) << "timeZone differs";
268  return false;
269  }
270 
271  if (d->mGeo != addressee.d->mGeo) {
272  qCDebug(KCONTACTS_LOG) << "geo differs";
273  return false;
274  }
275 
276  if (d->mDepartment != addressee.d->mDepartment //
277  && !(d->mDepartment.isEmpty() && addressee.d->mDepartment.isEmpty())) {
278  qCDebug(KCONTACTS_LOG) << "department differs";
279  return false;
280  }
281 
282  if (d->mNote != addressee.d->mNote //
283  && !(d->mNote.isEmpty() && addressee.d->mNote.isEmpty())) {
284  qCDebug(KCONTACTS_LOG) << "note differs";
285  return false;
286  }
287 
288  if (d->mProductId != addressee.d->mProductId //
289  && !(d->mProductId.isEmpty() && addressee.d->mProductId.isEmpty())) {
290  qCDebug(KCONTACTS_LOG) << "productId differs";
291  return false;
292  }
293 
294  if (d->mSortString != addressee.d->mSortString //
295  && !(d->mSortString.isEmpty() && addressee.d->mSortString.isEmpty())) {
296  qCDebug(KCONTACTS_LOG) << "sortString differs";
297  return false;
298  }
299 
300  if (d->mSecrecy != addressee.d->mSecrecy) {
301  qCDebug(KCONTACTS_LOG) << "secrecy differs";
302  return false;
303  }
304 
305  if (d->mLogo != addressee.d->mLogo) {
306  qCDebug(KCONTACTS_LOG) << "logo differs";
307  return false;
308  }
309 
310  if (d->mPhoto != addressee.d->mPhoto) {
311  qCDebug(KCONTACTS_LOG) << "photo differs";
312  return false;
313  }
314 
315  if (d->mSound != addressee.d->mSound) {
316  qCDebug(KCONTACTS_LOG) << "sound differs";
317  return false;
318  }
319 
320  if (!listEquals(d->mPhoneNumbers, addressee.d->mPhoneNumbers)) {
321  qCDebug(KCONTACTS_LOG) << "phoneNumbers differs";
322  return false;
323  }
324 
325  if (!listEquals(d->mAddresses, addressee.d->mAddresses)) {
326  qCDebug(KCONTACTS_LOG) << "addresses differs";
327  return false;
328  }
329 
330  if (!listEquals(d->mKeys, addressee.d->mKeys)) {
331  qCDebug(KCONTACTS_LOG) << "keys differs";
332  return false;
333  }
334  if (!listEquals(d->mEmails, addressee.d->mEmails)) {
335  qCDebug(KCONTACTS_LOG) << "emails differs";
336  return false;
337  }
338 
339  if (!listEquals(d->mCategories, addressee.d->mCategories)) {
340  qCDebug(KCONTACTS_LOG) << "categories differs";
341  return false;
342  }
343 
344  if (d->mCustomFields != addressee.d->mCustomFields) {
345  qCDebug(KCONTACTS_LOG) << "custom differs";
346  return false;
347  }
348  if (d->mLangs != addressee.d->mLangs) {
349  qCDebug(KCONTACTS_LOG) << "langs differs";
350  return false;
351  }
352  if (d->mImpps != addressee.d->mImpps) {
353  qCDebug(KCONTACTS_LOG) << "impps differs";
354  return false;
355  }
356  if (d->mGender != addressee.d->mGender) {
357  qCDebug(KCONTACTS_LOG) << "gender differs";
358  return false;
359  }
360  if (d->mKind != addressee.d->mKind) {
361  qCDebug(KCONTACTS_LOG) << "kind differs";
362  return false;
363  }
364  if (!listEquals(d->mCalendarUrl, addressee.d->mCalendarUrl)) {
365  qCDebug(KCONTACTS_LOG) << "calendarUrl differs";
366  return false;
367  }
368  if (!listEquals(d->mSoundListExtra, addressee.d->mSoundListExtra)) {
369  qCDebug(KCONTACTS_LOG) << "Extra sound differs";
370  return false;
371  }
372  if (!listEquals(d->mPhotoExtraList, addressee.d->mPhotoExtraList)) {
373  qCDebug(KCONTACTS_LOG) << "Extra photo differs";
374  return false;
375  }
376  if (!listEquals(d->mLogoExtraList, addressee.d->mLogoExtraList)) {
377  qCDebug(KCONTACTS_LOG) << "Extra logo differs";
378  return false;
379  }
380  if (!listEquals(d->mUrlExtraList, addressee.d->mUrlExtraList)) {
381  qCDebug(KCONTACTS_LOG) << "Extra url differs";
382  return false;
383  }
384  if (!listEquals(d->mMembers, addressee.d->mMembers)) {
385  qCDebug(KCONTACTS_LOG) << "Extra url differs";
386  return false;
387  }
388  if (!listEquals(d->mRelationships, addressee.d->mRelationships)) {
389  qCDebug(KCONTACTS_LOG) << "Relationships differs";
390  return false;
391  }
392  if (!listEquals(d->mSources, addressee.d->mSources)) {
393  qCDebug(KCONTACTS_LOG) << "Sources differs";
394  return false;
395  }
396 
397  if (!listEquals(d->mFieldGroupList, addressee.d->mFieldGroupList)) {
398  qCDebug(KCONTACTS_LOG) << "Field Groups differs";
399  return false;
400  }
401 
402  if (!listEquals(d->mTitleExtraList, addressee.d->mTitleExtraList)) {
403  qCDebug(KCONTACTS_LOG) << "Extra TitleList differs";
404  return false;
405  }
406 
407  if (!listEquals(d->mRoleExtraList, addressee.d->mRoleExtraList)) {
408  qCDebug(KCONTACTS_LOG) << "Extra RoleList differs";
409  return false;
410  }
411 
412  if (!listEquals(d->mOrgExtraList, addressee.d->mOrgExtraList)) {
413  qCDebug(KCONTACTS_LOG) << "Extra Organization List differs";
414  return false;
415  }
416 
417  if (!listEquals(d->mNickNameExtraList, addressee.d->mNickNameExtraList)) {
418  qCDebug(KCONTACTS_LOG) << "Extra NickName List differs";
419  return false;
420  }
421 
422  if (!listEquals(d->mClientPidMapList, addressee.d->mClientPidMapList)) {
423  qCDebug(KCONTACTS_LOG) << "ClientPidMap List differs";
424  return false;
425  }
426  return true;
427 }
428 
429 bool Addressee::operator!=(const Addressee &a) const
430 {
431  return !(a == *this);
432 }
433 
434 bool Addressee::isEmpty() const
435 {
436  return d->mEmpty;
437 }
438 
439 void Addressee::setUid(const QString &id)
440 {
441  if (id == d->mUid) {
442  return;
443  }
444 
445  d->mEmpty = false;
446  d->mUid = id;
447 }
448 
449 QString Addressee::uid() const
450 {
451  return d->mUid;
452 }
453 
455 {
456  return i18n("Unique Identifier");
457 }
458 
459 void Addressee::setName(const QString &name)
460 {
461  if (name == d->mName) {
462  return;
463  }
464 
465  d->mEmpty = false;
466  d->mName = name;
467 }
468 
469 QString Addressee::name() const
470 {
471  return d->mName;
472 }
473 
475 {
476  return i18n("Name");
477 }
478 
479 void Addressee::setKind(const QString &kind)
480 {
481  if (kind == d->mKind) {
482  return;
483  }
484 
485  d->mEmpty = false;
486  d->mKind = kind;
487 }
488 
489 QString Addressee::kind() const
490 {
491  return d->mKind;
492 }
493 
494 void Addressee::insertExtraSound(const Sound &sound)
495 {
496  d->mEmpty = false;
497  d->mSoundListExtra.append(sound);
498 }
499 
500 Sound::List Addressee::extraSoundList() const
501 {
502  return d->mSoundListExtra;
503 }
504 
505 void Addressee::insertExtraPhoto(const Picture &picture)
506 {
507  d->mEmpty = false;
508  d->mPhotoExtraList.append(picture);
509 }
510 
511 Picture::List Addressee::extraPhotoList() const
512 {
513  return d->mPhotoExtraList;
514 }
515 
516 void Addressee::insertExtraLogo(const Picture &logo)
517 {
518  d->mEmpty = false;
519  d->mLogoExtraList.append(logo);
520 }
521 
522 Picture::List Addressee::extraLogoList() const
523 {
524  return d->mLogoExtraList;
525 }
526 
527 void Addressee::setExtraSoundList(const Sound::List &soundList)
528 {
529  d->mEmpty = false;
530  d->mSoundListExtra = soundList;
531 }
532 
533 void Addressee::setExtraPhotoList(const Picture::List &pictureList)
534 {
535  d->mEmpty = false;
536  d->mPhotoExtraList = pictureList;
537 }
538 
539 void Addressee::setExtraLogoList(const Picture::List &logoList)
540 {
541  d->mEmpty = false;
542  d->mLogoExtraList = logoList;
543 }
544 
545 void Addressee::insertExtraUrl(const ResourceLocatorUrl &url)
546 {
547  if (url.isValid()) {
548  d->mEmpty = false;
549  d->mUrlExtraList.append(url);
550  }
551 }
552 
553 void Addressee::setExtraUrlList(const ResourceLocatorUrl::List &urlList)
554 {
555  d->mEmpty = false;
556  d->mUrlExtraList = urlList;
557 }
558 
559 ResourceLocatorUrl::List Addressee::extraUrlList() const
560 {
561  return d->mUrlExtraList;
562 }
563 
564 void Addressee::insertSourceUrl(const QUrl &url)
565 {
566  d->mEmpty = false;
567  d->mSources.append(url);
568 }
569 
570 void Addressee::setSourcesUrlList(const QVector<QUrl> &urlList)
571 {
572  d->mEmpty = false;
573  d->mSources = urlList;
574 }
575 
576 QVector<QUrl> Addressee::sourcesUrlList() const
577 {
578  return d->mSources;
579 }
580 
581 FieldGroup::List Addressee::fieldGroupList() const
582 {
583  return d->mFieldGroupList;
584 }
585 
586 void Addressee::setFieldGroupList(const FieldGroup::List &fieldGroupList)
587 {
588  d->mEmpty = false;
589  d->mFieldGroupList = fieldGroupList;
590 }
591 
592 void Addressee::insertFieldGroup(const FieldGroup &fieldGroup)
593 {
594  if (fieldGroup.isValid()) {
595  d->mEmpty = false;
596  // TODO don't duplicate ?
597  d->mFieldGroupList.append(fieldGroup);
598  }
599 }
600 
601 ClientPidMap::List Addressee::clientPidMapList() const
602 {
603  return d->mClientPidMapList;
604 }
605 
606 void Addressee::setClientPidMapList(const ClientPidMap::List &clientpidmaplist)
607 {
608  d->mEmpty = false;
609  d->mClientPidMapList = clientpidmaplist;
610 }
611 
612 void Addressee::insertClientPidMap(const ClientPidMap &clientpidmap)
613 {
614  if (clientpidmap.isValid()) {
615  d->mEmpty = false;
616  // TODO don't duplicate ?
617  d->mClientPidMapList.append(clientpidmap);
618  }
619 }
620 
621 void Addressee::insertImpp(const Impp &impp)
622 {
623  if (impp.isValid()) {
624  d->mEmpty = false;
625  // Don't duplicate ?
626  d->mImpps.append(impp);
627  }
628 }
629 
630 void Addressee::setImppList(const Impp::List &imppList)
631 {
632  d->mEmpty = false;
633  d->mImpps = imppList;
634 }
635 
636 Impp::List Addressee::imppList() const
637 {
638  return d->mImpps;
639 }
640 
641 void Addressee::insertCalendarUrl(const CalendarUrl &calendarUrl)
642 {
643  d->mEmpty = false;
644  // TODO verify that there is not same calendarurl
645  if (calendarUrl.isValid()) {
646  d->mCalendarUrl.append(calendarUrl);
647  }
648 }
649 
650 CalendarUrl::List Addressee::calendarUrlList() const
651 {
652  return d->mCalendarUrl;
653 }
654 
655 void Addressee::setFormattedName(const QString &formattedName)
656 {
657  if (formattedName == d->mFormattedName) {
658  return;
659  }
660 
661  d->mEmpty = false;
662  d->mFormattedName = formattedName;
663 }
664 
665 QString Addressee::formattedName() const
666 {
667  return d->mFormattedName;
668 }
669 
671 {
672  return i18n("Formatted Name");
673 }
674 
675 void Addressee::setFamilyName(const QString &familyName)
676 {
677  if (familyName == d->mFamilyName) {
678  return;
679  }
680 
681  d->mEmpty = false;
682  d->mFamilyName = familyName;
683 }
684 
685 QString Addressee::familyName() const
686 {
687  return d->mFamilyName;
688 }
689 
691 {
692  return i18n("Family Name");
693 }
694 
695 void Addressee::setGivenName(const QString &givenName)
696 {
697  if (givenName == d->mGivenName) {
698  return;
699  }
700 
701  d->mEmpty = false;
702  d->mGivenName = givenName;
703 }
704 
705 QString Addressee::givenName() const
706 {
707  return d->mGivenName;
708 }
709 
711 {
712  return i18n("Given Name");
713 }
714 
715 void Addressee::setAdditionalName(const QString &additionalName)
716 {
717  if (additionalName == d->mAdditionalName) {
718  return;
719  }
720 
721  d->mEmpty = false;
722  d->mAdditionalName = additionalName;
723 }
724 
725 QString Addressee::additionalName() const
726 {
727  return d->mAdditionalName;
728 }
729 
731 {
732  return i18n("Additional Names");
733 }
734 
735 void Addressee::setPrefix(const QString &prefix)
736 {
737  if (prefix == d->mPrefix) {
738  return;
739  }
740 
741  d->mEmpty = false;
742  d->mPrefix = prefix;
743 }
744 
745 QString Addressee::prefix() const
746 {
747  return d->mPrefix;
748 }
749 
751 {
752  return i18n("Honorific Prefixes");
753 }
754 
755 void Addressee::setSuffix(const QString &suffix)
756 {
757  if (suffix == d->mSuffix) {
758  return;
759  }
760 
761  d->mEmpty = false;
762  d->mSuffix = suffix;
763 }
764 
765 QString Addressee::suffix() const
766 {
767  return d->mSuffix;
768 }
769 
771 {
772  return i18n("Honorific Suffixes");
773 }
774 
775 void Addressee::setNickName(const QString &nickName)
776 {
777  NickName t(nickName);
778  if (!d->mNickNameExtraList.isEmpty()) {
779  t = d->mNickNameExtraList.takeFirst();
780  t.setNickName(nickName);
781  d->mNickNameExtraList.prepend(t);
782  d->mEmpty = false;
783  } else {
784  insertExtraNickName(t);
785  }
786 }
787 
788 void Addressee::setNickName(const NickName &nickName)
789 {
790  insertExtraNickName(nickName);
791 }
792 
793 void Addressee::insertExtraNickName(const NickName &nickName)
794 {
795  if (nickName.isValid()) {
796  d->mEmpty = false;
797  d->mNickNameExtraList.append(nickName);
798  }
799 }
800 
801 void Addressee::setExtraNickNameList(const NickName::List &nickNameList)
802 {
803  d->mEmpty = false;
804  d->mNickNameExtraList = nickNameList;
805 }
806 
807 NickName::List Addressee::extraNickNameList() const
808 {
809  return d->mNickNameExtraList;
810 }
811 
812 QString Addressee::nickName() const
813 {
814  if (d->mNickNameExtraList.isEmpty()) {
815  return {};
816  } else {
817  return d->mNickNameExtraList.at(0).nickname();
818  }
819 }
820 
822 {
823  return i18n("Nick Name");
824 }
825 
826 void Addressee::setBirthday(const QDateTime &birthday, bool withTime)
827 {
828  if (birthday == d->mBirthday && d->mBirthdayWithTime == withTime) {
829  return;
830  }
831 
832  d->mEmpty = false;
833  d->mBirthday = birthday;
834  if (!withTime) {
835  d->mBirthday.setTime(QTime());
836  }
837  d->mBirthdayWithTime = withTime;
838 }
839 
840 void Addressee::setBirthday(const QDate &birthday)
841 {
842  if (birthday == d->mBirthday.date() && !d->mBirthdayWithTime) {
843  return;
844  }
845 
846  d->mEmpty = false;
847  d->mBirthday = QDateTime(birthday, QTime());
848  d->mBirthdayWithTime = false;
849 }
850 
851 QDateTime Addressee::birthday() const
852 {
853  return d->mBirthday;
854 }
855 
856 bool Addressee::birthdayHasTime() const
857 {
858  return d->mBirthdayWithTime;
859 }
860 
862 {
863  return i18n("Birthday");
864 }
865 
867 {
868  return i18n("Home Address Street");
869 }
870 
872 {
873  return i18n("Home Address Post Office Box");
874 }
875 
877 {
878  return i18n("Home Address City");
879 }
880 
882 {
883  return i18n("Home Address State");
884 }
885 
887 {
888  return i18n("Home Address Zip Code");
889 }
890 
892 {
893  return i18n("Home Address Country");
894 }
895 
897 {
898  return i18n("Home Address Label");
899 }
900 
902 {
903  return i18n("Business Address Street");
904 }
905 
907 {
908  return i18n("Business Address Post Office Box");
909 }
910 
912 {
913  return i18n("Business Address City");
914 }
915 
917 {
918  return i18n("Business Address State");
919 }
920 
922 {
923  return i18n("Business Address Zip Code");
924 }
925 
927 {
928  return i18n("Business Address Country");
929 }
930 
932 {
933  return i18n("Business Address Label");
934 }
935 
937 {
938  return i18n("Home Phone");
939 }
940 
942 {
943  return i18n("Business Phone");
944 }
945 
947 {
948  return i18n("Mobile Phone");
949 }
950 
952 {
953  return i18n("Home Fax");
954 }
955 
957 {
958  return i18n("Business Fax");
959 }
960 
962 {
963  return i18n("Car Phone");
964 }
965 
967 {
968  return i18n("ISDN");
969 }
970 
972 {
973  return i18n("Pager");
974 }
975 
977 {
978  return i18n("Email Address");
979 }
980 
981 void Addressee::setMailer(const QString &mailer)
982 {
983  if (mailer == d->mMailer) {
984  return;
985  }
986 
987  d->mEmpty = false;
988  d->mMailer = mailer;
989 }
990 
991 QString Addressee::mailer() const
992 {
993  return d->mMailer;
994 }
995 
997 {
998  return i18n("Mail Client");
999 }
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 
1012 {
1013  return d->mTimeZone;
1014 }
1015 
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 
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 
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 
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 
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 
1210 {
1211  return i18n("Department");
1212 }
1213 
1214 void Addressee::setNote(const QString &note)
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 
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 
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 
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 
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 
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 
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 
1331 {
1332  return d->mSecrecy;
1333 }
1334 
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 
1351 {
1352  return d->mLogo;
1353 }
1354 
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 
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 
1391 {
1392  return d->mSound;
1393 }
1394 
1396 {
1397  return i18n("Sound");
1398 }
1399 
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());
1416  setSuffix(QString());
1417 
1418  if (str.isEmpty()) {
1419  return;
1420  }
1421 
1422  static QString spaceStr = QStringLiteral(" ");
1423  static QString emptyStr = QStringLiteral("");
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());
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());
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 
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> &param)
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 
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 
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 
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 
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 
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 
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 
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 
1897 {
1898  d->mKeys = list;
1899  d->mEmpty = false;
1900 }
1901 
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 
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 
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 
2044 {
2045  d->mEmpty = false;
2046  d->mAddresses = addresses;
2047 }
2048 
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 
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 
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 
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 
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 
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"
static QString productIdLabel()
Return translated label for productId field.
Definition: addressee.cpp:1249
Time zone information.
Definition: timezone.h:22
static QString mobilePhoneLabel()
Return translated label for mobilePhone field.
Definition: addressee.cpp:946
static QString organizationLabel()
Return translated label for organization field.
Definition: addressee.cpp:1189
bool endsWith(const QString &s, Qt::CaseSensitivity cs) const const
bool isNull() const const
void setSound(const Sound &sound)
Set sound.
Definition: addressee.cpp:1380
This singleton class stores static data, which is shared by all Addressee objects.
A class to store a picture of an addressee.
Definition: picture.h:26
~Addressee()
Destroys the address book entry.
Definition: addressee.cpp:187
Class that holds a Title for a contact.
Definition: title.h:26
void removeAddress(const Address &address)
Remove address.
Definition: addressee.cpp:2033
Class that holds a Language for a contact.
Definition: lang.h:26
void setPhoto(const Picture &photo)
Set photo.
Definition: addressee.cpp:1360
Class that holds a Email for a contact.
Definition: email.h:27
void setSuffix(const QString &suffix)
Set honorific suffixes.
Definition: addressee.cpp:755
static QString homeAddressStreetLabel()
Return translated label for homeAddressStreet field.
Definition: addressee.cpp:866
@ Custom
Custom or IANA conform key.
Definition: key.h:38
void setMailer(const QString &mailer)
Set mail client.
Definition: addressee.cpp:981
QString fromUtf8(const char *str, int size)
QString customTypeString() const
Returns the custom type string.
Definition: key.cpp:159
void removeLang(const QString &language)
Remove Language.
Definition: addressee.cpp:1724
static QString homePhoneLabel()
Return translated label for homePhone field.
Definition: addressee.cpp:936
static QString businessAddressLocalityLabel()
Return translated label for businessAddressLocality field.
Definition: addressee.cpp:911
void removePhoneNumber(const PhoneNumber &phoneNumber)
Remove phone number.
Definition: addressee.cpp:1795
Lang::List langs() const
langs
Definition: addressee.cpp:1758
void setAddresses(const Address::List &addresses)
Set the addressee.
Definition: addressee.cpp:2043
QString pattern(Mode mode=Reading)
void stop(Ekos::AlignState mode)
bool treatAsFamilyName() const
Returns whether or not a single name component should be interpreted as a family name.
QString custom(const QString &app, const QString &name) const
Return value of custom entry, identified by app and entry name.
Definition: addressee.cpp:2304
void setAssistantsName(const QString &assistantsName)
Set the contact's assistant's name.
Definition: addressee.cpp:2196
QVector::iterator begin()
void setLogo(const Picture &logo)
Set logo.
Definition: addressee.cpp:1340
QStringList split(const QString &sep, QString::SplitBehavior behavior, Qt::CaseSensitivity cs) const const
StandardShortcut findByName(const QString &name)
int count(const T &value) const const
void setSecrecy(const Secrecy &secrecy)
Set security class.
Definition: addressee.cpp:1320
static QString revisionLabel()
Return translated label for revision field.
Definition: addressee.cpp:1269
bool contains(const QString &str, Qt::CaseSensitivity cs) const const
QTime time() const const
QString trimmed() const const
void clear()
QString url(QUrl::FormattingOptions options) const const
QString toString() const
Returns string representation of the addressee.
Definition: addressee.cpp:1941
PhoneNumber phoneNumber(PhoneNumber::Type type) const
Return phone number, which matches the given type.
Definition: addressee.cpp:1806
QString & prepend(QChar ch)
static QString businessAddressStreetLabel()
Return translated label for businessAddressStreet field.
Definition: addressee.cpp:901
void setRole(const QString &role)
Set role.
Definition: addressee.cpp:1092
void setProfession(const QString &profession)
Set the contact's profession.
Definition: addressee.cpp:2252
void setRevision(const QDateTime &revision)
Set revision date.
Definition: addressee.cpp:1254
Describes the confidentiality of an addressee.
Definition: secrecy.h:18
QByteArray trimmed() const const
void push_back(const T &value)
Class that holds a Role for a contact.
Definition: role.h:26
void setBirthday(const QDateTime &birthday, bool withTime=true)
Set birthday (date and time).
Definition: addressee.cpp:826
@ Pref
preferred address
Definition: address.h:85
static QString soundLabel()
Return translated label for sound field.
Definition: addressee.cpp:1395
Postal address information.
Definition: address.h:30
static QString sortStringLabel()
Return translated label for sortString field.
Definition: addressee.cpp:1289
KIOFILEWIDGETS_EXPORT QStringList list(const QString &fileClass)
static QString timeZoneLabel()
Return translated label for timeZone field.
Definition: addressee.cpp:1016
void setFormattedName(const QString &formattedName)
Set formatted name.
Definition: addressee.cpp:655
void setGivenName(const QString &givenName)
Set given name.
Definition: addressee.cpp:695
void setAnniversary(const QDate &anniversary)
Sets the contact's anniversary date.
Definition: addressee.cpp:2182
static QString logoLabel()
Return translated label for logo field.
Definition: addressee.cpp:1355
void removeEmail(const QString &email)
Remove email address.
Definition: addressee.cpp:1672
void setDepartment(const QString &department)
Set department.
Definition: addressee.cpp:1194
static QString emailLabel()
Return translated label for email field.
Definition: addressee.cpp:976
Class that holds a FieldGroup for a contact.
Definition: fieldgroup.h:26
QString simplified() const const
Addressee & operator=(const Addressee &other)
Assignment operator.
Definition: addressee.cpp:196
static QString businessPhoneLabel()
Return translated label for businessPhone field.
Definition: addressee.cpp:941
void setAdditionalName(const QString &additionalName)
Set additional names.
Definition: addressee.cpp:715
static QString homeAddressLabelLabel()
Return translated label for homeAddressLabel field.
Definition: addressee.cpp:896
address book entry
Definition: addressee.h:69
void setCategories(const QStringList &category)
Set categories to given value.
Definition: addressee.cpp:2112
static QString suffixLabel()
Return translated label for suffix field.
Definition: addressee.cpp:770
Picture logo() const
Return logo.
Definition: addressee.cpp:1350
void reserve(int alloc)
static QString roleLabel()
Return translated label for role field.
Definition: addressee.cpp:1138
static QString mailerLabel()
Return translated label for mailer field.
Definition: addressee.cpp:996
static QString nickNameLabel()
Return translated label for nickName field.
Definition: addressee.cpp:821
int size() const const
static QString formattedNameLabel()
Return translated label for formattedName field.
Definition: addressee.cpp:670
A class to store an encryption key.
Definition: key.h:21
Geographic position.
Definition: geo.h:24
bool operator==(const Qt3DRender::QGraphicsApiFilter &reference, const Qt3DRender::QGraphicsApiFilter &sample)
static void parseEmailAddress(const QString &rawEmail, QString &fullName, QString &email)
Parse full email address.
Definition: addressee.cpp:2349
QString i18n(const char *text, const TYPE &arg...)
Class that holds a Resource Locator.
static QString homeAddressPostOfficeBoxLabel()
Return translated label for homeAddressPostOfficeBox field.
Definition: addressee.cpp:871
static QString prefixLabel()
Return translated label for prefix field.
Definition: addressee.cpp:750
bool isEmpty() const const
void insertAddress(const Address &address)
Insert an address.
Definition: addressee.cpp:2014
static QString noteLabel()
Return translated label for note field.
Definition: addressee.cpp:1229
bool operator!=(const Addressee &other) const
Not-equal operator.
Definition: addressee.cpp:429
static QString birthdayLabel()
Return translated label for birthday field.
Definition: addressee.cpp:861
bool isEmpty() const const
QByteArray toUtf8() const const
int length() const const
void setCustoms(const QStringList &customs)
Set all custom entries.
Definition: addressee.cpp:2311
void setEmails(const QStringList &list)
Set the emails to list.
Definition: addressee.cpp:1707
void setFamilyName(const QString &familyName)
Set family name.
Definition: addressee.cpp:675
const T & at(int i) const const
bool operator!=(const Qt3DRender::QGraphicsApiFilter &reference, const Qt3DRender::QGraphicsApiFilter &sample)
Secrecy secrecy() const
Return security class.
Definition: addressee.cpp:1330
void insertEmail(const QString &email, bool preferred=false, const QMap< QString, QStringList > &param=QMap< QString, QStringList >())
Insert an email address.
Definition: addressee.cpp:1644
Address address(Address::Type type) const
Return address, which matches the given type.
Definition: addressee.cpp:2049
bool isValid() const const
static QString homeAddressPostalCodeLabel()
Return translated label for homeAddressPostalCode field.
Definition: addressee.cpp:886
bool isEmpty() const const
void setTitle(const QString &title)
Set title.
Definition: addressee.cpp:1041
void setSpousesName(const QString &spousesName)
Set the contact's spouse's name.
Definition: addressee.cpp:2266
Address findAddress(const QString &id) const
Return address with the given id.
Definition: addressee.cpp:2081
void setOffice(const QString &office)
Set the contact's office.
Definition: addressee.cpp:2238
void insertKey(const Key &key)
Insert a key.
Definition: addressee.cpp:1854
void setPrefix(const QString &prefix)
Set honorific prefixes.
Definition: addressee.cpp:735
void setOrganization(const QString &organization)
Set organization.
Definition: addressee.cpp:1143
int indexOf(QChar ch, int from, Qt::CaseSensitivity cs) const const
void setGeo(const Geo &geo)
Set geographic position.
Definition: addressee.cpp:1021
Key::List keys() const
Return list of all keys.
Definition: addressee.cpp:1902
void setChanged(bool value)
Mark addressee as changed.
Definition: addressee.cpp:2528
Type
Key types.
Definition: key.h:35
static QString secrecyLabel()
Return translated label for secrecy field.
Definition: addressee.cpp:1335
static QString businessAddressCountryLabel()
Return translated label for businessAddressCountry field.
Definition: addressee.cpp:926
static QString uidLabel()
Return translated label for uid field.
Definition: addressee.cpp:454
void reserve(int size)
static QString businessAddressLabelLabel()
Return translated label for businessAddressLabel field.
Definition: addressee.cpp:931
static QString homeAddressLocalityLabel()
Return translated label for homeAddressLocality field.
Definition: addressee.cpp:876
static QString businessAddressPostalCodeLabel()
Return translated label for businessAddressPostalCode field.
Definition: addressee.cpp:921
QString & replace(int position, int n, QChar after)
void setNote(const QString &note)
Set note.
Definition: addressee.cpp:1214
void insertCustom(const QString &app, const QString &name, const QString &value)
Insert custom entry.
Definition: addressee.cpp:2275
bool startsWith(const QString &s, Qt::CaseSensitivity cs) const const
Describes a relationship of an Addressee.
Definition: related.h:24
Type type() const
Returns the type, see Type.
Definition: key.cpp:154
QVector::iterator end()
TimeZone timeZone() const
Return time zone.
Definition: addressee.cpp:1011
QString toLower() const const
QDate fromString(const QString &string, Qt::DateFormat format)
static QString carPhoneLabel()
Return translated label for carPhone field.
Definition: addressee.cpp:961
void setName(const QString &name)
Set name.
Definition: addressee.cpp:459
bool isEmpty() const const
void setUrl(const ResourceLocatorUrl &url)
Set homepage.
Definition: addressee.cpp:1301
static AddresseeHelper * self()
Singleton interface to this class.
int count() const const
bool operator==(const Addressee &other) const
Equality operator.
Definition: addressee.cpp:205
void setNameFromString(const QString &s)
Set name fields by parsing the given string and trying to associate the parts of the string with acco...
Definition: addressee.cpp:1400
QString fullEmail(const QString &email=QString()) const
Return email address including real name.
Definition: addressee.cpp:1590
Class that holds a NickName for a contact.
Definition: nickname.h:26
bool containsTitle(const QString &title) const
Queries the list of honoric prefixes.
Class that holds a Gender for a contact.
Definition: gender.h:19
QString arg(qlonglong a, int fieldWidth, int base, QChar fillChar) const const
static QString geoLabel()
Return translated label for geo field.
Definition: addressee.cpp:1036
static QString additionalNameLabel()
Return translated label for additionalName field.
Definition: addressee.cpp:730
QString left(int n) const const
bool containsPrefix(const QString &prefix) const
Queries the list of inclusions.
void insertPhoneNumber(const PhoneNumber &phoneNumber)
Insert a phone number.
Definition: addressee.cpp:1778
QString name(StandardShortcut id)
static QString homeAddressRegionLabel()
Return translated label for homeAddressRegion field.
Definition: addressee.cpp:881
void removeCategory(const QString &category)
Remove category.
Definition: addressee.cpp:2100
static QString pagerLabel()
Return translated label for pager field.
Definition: addressee.cpp:971
Sound sound() const
Return sound.
Definition: addressee.cpp:1390
Class that holds a Organization for a contact.
Definition: org.h:26
int msecsSinceStartOfDay() const const
void setManagersName(const QString &managersName)
Set the contact's manager's name.
Definition: addressee.cpp:2224
static QString familyNameLabel()
Return translated label for familyName field.
Definition: addressee.cpp:690
static QString titleLabel()
Return translated label for title field.
Definition: addressee.cpp:1087
static QString homeAddressCountryLabel()
Return translated label for homeAddressCountry field.
Definition: addressee.cpp:891
QString i18nc(const char *context, const char *text, const TYPE &arg...)
Key findKey(const QString &id) const
Return key with the given id.
Definition: addressee.cpp:1932
void addEmail(const Email &email)
Adds an email address.
Definition: addressee.cpp:1619
QString toString(Qt::DateFormat format) const const
void removeCustom(const QString &app, const QString &name)
Remove custom entry.
Definition: addressee.cpp:2295
static QString urlLabel()
Return translated label for url field.
Definition: addressee.cpp:1315
Addressee()
Construct an empty address book entry.
Definition: addressee.cpp:182
Class that holds a Sound clip for a contact.
Definition: sound.h:45
int size() const const
void setNickName(const QString &nickName)
Set nick name.
Definition: addressee.cpp:775
Phonenumber information.
Definition: phonenumber.h:30
PhoneNumber findPhoneNumber(const QString &id) const
Return phone number with the given id.
Definition: addressee.cpp:1845
static QString givenNameLabel()
Return translated label for givenName field.
Definition: addressee.cpp:710
void setBlogFeed(const QUrl &blogFeed)
Set the contact's blog feed.
Definition: addressee.cpp:2210
void setTimeZone(const TimeZone &timeZone)
Set time zone.
Definition: addressee.cpp:1001
void setSortString(const QString &sortString)
Set sort string.
Definition: addressee.cpp:1274
@ Pref
Preferred number.
Definition: phonenumber.h:55
bool hasCategory(const QString &category) const
Return, if addressee has the given category.
Definition: addressee.cpp:2107
bool contains(QChar ch, Qt::CaseSensitivity cs) const const
Class that holds a IMPP for a contact.
Definition: impp.h:31
static QString nameLabel()
Return translated label for name field.
Definition: addressee.cpp:474
static QString businessFaxLabel()
Return translated label for businessFax field.
Definition: addressee.cpp:956
Class that holds a ClientPidMap for a contact.
Definition: clientpidmap.h:26
Key key(Key::Type type, const QString &customTypeString=QString()) const
Return key, which matches the given type.
Definition: addressee.cpp:1876
static QString businessAddressRegionLabel()
Return translated label for businessAddressRegion field.
Definition: addressee.cpp:916
QString mid(int position, int n) const const
void setKeys(const Key::List &keys)
Set the list of keys.
Definition: addressee.cpp:1896
Class that holds a Calendar Url (FBURL/CALADRURI/CALURI)
Definition: calendarurl.h:26
static QString homeFaxLabel()
Return translated label for homeFax field.
Definition: addressee.cpp:951
QString & append(QChar ch)
void removeKey(const Key &key)
Remove a key.
Definition: addressee.cpp:1868
static QString businessAddressPostOfficeBoxLabel()
Return translated label for businessAddressPostOfficeBox field.
Definition: addressee.cpp:906
char * toString(const EngineQuery &query)
static QString mimeType()
Returns the MIME type used for Addressees.
Definition: addressee.cpp:2538
static QString photoLabel()
Return translated label for photo field.
Definition: addressee.cpp:1375
bool containsSuffix(const QString &suffix) const
Queries the list of honoric suffixes.
static QString departmentLabel()
Return translated label for department field.
Definition: addressee.cpp:1209
void setProductId(const QString &productId)
Set product identifier.
Definition: addressee.cpp:1234
void insertCategory(const QString &category)
Insert category.
Definition: addressee.cpp:2089
void insertLang(const Lang &language)
Insert Language.
Definition: addressee.cpp:1739
static QString isdnLabel()
Return translated label for isdn field.
Definition: addressee.cpp:966
void setUid(const QString &uid)
Set unique identifier.
Definition: addressee.cpp:439
This file is part of the KDE documentation.
Documentation copyright © 1996-2023 The KDE developers.
Generated on Thu Dec 7 2023 04:12:55 by doxygen 1.8.17 written by Dimitri van Heesch, © 1997-2006

KDE's Doxygen guidelines are available online.