1/*
2 This file is part of libkabc.
3 Copyright (c) 2001 Cornelius Schumacher <schumacher@kde.org>
4 Copyright (c) 2003 Carsten Pfeiffer <pfeiffer@kde.org>
5 Copyright (c) 2005 Ingo Kloecker <kloecker@kde.org>
6
7 This library is free software; you can redistribute it and/or
8 modify it under the terms of the GNU Library General Public
9 License as published by the Free Software Foundation; either
10 version 2 of the License, or (at your option) any later version.
11
12 This library is distributed in the hope that it will be useful,
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 Library General Public License for more details.
16
17 You should have received a copy of the GNU Library General Public License
18 along with this library; see the file COPYING.LIB. If not, write to
19 the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
20 Boston, MA 02110-1301, USA.
21*/
22
23#include <QtCore/QList>
24#include <QtCore/QRegExp>
25#include <QtCore/QSharedData>
26#include <QtCore/QUuid>
27
28#include <kdebug.h>
29#include <klocale.h>
30#include <klocalizedstring.h>
31
32#include "addresseehelper.h"
33#include "field.h"
34#ifndef KDEPIM_NO_KRESOURCES
35#include "resource.h"
36#endif
37#include "sortmode.h"
38
39#include "addressee.h"
40
41using namespace KABC;
42
43static bool matchBinaryPattern( int value, int pattern );
44
45template <class L>
46static bool listEquals( const QList<L>&, const QList<L>& );
47static bool listEquals( const QStringList&, const QStringList& );
48static bool emailsEquals( const QStringList&, const QStringList& );
49
50class Addressee::Private : public QSharedData
51{
52 public:
53 Private()
54 : mUid( QUuid::createUuid().toString().mid(1, 36) ), //We avoid the curly braces so the string is RFC4122 compliant and can be used as urn
55#ifndef KDEPIM_NO_KRESOURCES
56 mResource( 0 ),
57#endif
58 mEmpty( true ), mChanged( false )
59 {
60 }
61
62 Private( const Private &other )
63 : QSharedData( other )
64#ifndef KDEPIM_NO_KRESOURCES
65 ,mResource( 0 )
66#endif
67 {
68 mUid = other.mUid;
69 mName = other.mName;
70 mFormattedName = other.mFormattedName;
71 mFamilyName = other.mFamilyName;
72 mGivenName = other.mGivenName;
73 mAdditionalName = other.mAdditionalName;
74 mPrefix = other.mPrefix;
75 mSuffix = other.mSuffix;
76 mNickName = other.mNickName;
77 mBirthday = other.mBirthday;
78 mMailer = other.mMailer;
79 mTimeZone = other.mTimeZone;
80 mGeo = other.mGeo;
81 mTitle = other.mTitle;
82 mRole = other.mRole;
83 mOrganization = other.mOrganization;
84 mDepartment = other.mDepartment;
85 mNote = other.mNote;
86 mProductId = other.mProductId;
87 mRevision = other.mRevision;
88 mSortString = other.mSortString;
89 mUrl = other.mUrl;
90 mSecrecy = other.mSecrecy;
91 mLogo = other.mLogo;
92 mPhoto = other.mPhoto;
93 mSound = other.mSound;
94
95 mPhoneNumbers = other.mPhoneNumbers;
96 mAddresses = other.mAddresses;
97 mKeys = other.mKeys;
98 mEmails = other.mEmails;
99 mCategories = other.mCategories;
100 mCustomFields = other.mCustomFields;
101
102#ifndef KDEPIM_NO_KRESOURCES
103 mResource = other.mResource;
104#endif
105 mEmpty = other.mEmpty;
106 mChanged = other.mChanged;
107 }
108
109 ~Private()
110 {
111 }
112
113 QString mUid;
114 QString mName;
115 QString mFormattedName;
116 QString mFamilyName;
117 QString mGivenName;
118 QString mAdditionalName;
119 QString mPrefix;
120 QString mSuffix;
121 QString mNickName;
122 QDateTime mBirthday;
123 QString mMailer;
124 TimeZone mTimeZone;
125 Geo mGeo;
126 QString mTitle;
127 QString mRole;
128 QString mOrganization;
129 QString mDepartment;
130 QString mNote;
131 QString mProductId;
132 QDateTime mRevision;
133 QString mSortString;
134 KUrl mUrl;
135 Secrecy mSecrecy;
136 Picture ;
137 Picture mPhoto;
138 Sound mSound;
139
140 PhoneNumber::List mPhoneNumbers;
141 Address::List mAddresses;
142 Key::List mKeys;
143 QStringList mEmails;
144 QStringList mCategories;
145 QMap<QString, QString> mCustomFields;
146
147#ifndef KDEPIM_NO_KRESOURCES
148 Resource *mResource;
149#endif
150
151 bool mEmpty :1;
152 bool mChanged :1;
153
154 static KABC::SortMode *mSortMode;
155};
156
157KABC::SortMode *Addressee::Private::mSortMode = 0;
158
159Addressee::Addressee()
160 : d( new Private )
161{
162}
163
164Addressee::~Addressee()
165{
166}
167
168Addressee::Addressee( const Addressee &other )
169 : d( other.d )
170{
171}
172
173Addressee& Addressee::operator=( const Addressee &other )
174{
175 if ( this != &other )
176 d = other.d;
177
178 return *this;
179}
180
181bool Addressee::operator==( const Addressee &addressee ) const
182{
183 if ( d->mUid != addressee.d->mUid ) {
184 kDebug() << "uid differs";
185 return false;
186 }
187
188 if ( d->mName != addressee.d->mName &&
189 !( d->mName.isEmpty() && addressee.d->mName.isEmpty() ) ) {
190 kDebug(5700) << "name differs";
191 return false;
192 }
193
194 if ( d->mFormattedName != addressee.d->mFormattedName &&
195 !( d->mFormattedName.isEmpty() && addressee.d->mFormattedName.isEmpty() ) ) {
196 kDebug(5700) << "formattedName differs";
197 return false;
198 }
199
200 if ( d->mFamilyName != addressee.d->mFamilyName &&
201 !( d->mFamilyName.isEmpty() && addressee.d->mFamilyName.isEmpty() ) ) {
202 kDebug(5700) << "familyName differs";
203 return false;
204 }
205
206 if ( d->mGivenName != addressee.d->mGivenName &&
207 !( d->mGivenName.isEmpty() && addressee.d->mGivenName.isEmpty() ) ) {
208 kDebug(5700) << "givenName differs";
209 return false;
210 }
211
212 if ( d->mAdditionalName != addressee.d->mAdditionalName &&
213 !( d->mAdditionalName.isEmpty() && addressee.d->mAdditionalName.isEmpty() ) ) {
214 kDebug(5700) << "additionalName differs";
215 return false;
216 }
217
218 if ( d->mPrefix != addressee.d->mPrefix &&
219 !( d->mPrefix.isEmpty() && addressee.d->mPrefix.isEmpty() ) ) {
220 kDebug(5700) << "prefix differs";
221 return false;
222 }
223
224 if ( d->mSuffix != addressee.d->mSuffix &&
225 !( d->mSuffix.isEmpty() && addressee.d->mSuffix.isEmpty() ) ) {
226 kDebug(5700) << "suffix differs";
227 return false;
228 }
229
230 if ( d->mNickName != addressee.d->mNickName &&
231 !( d->mNickName.isEmpty() && addressee.d->mNickName.isEmpty() ) ) {
232 kDebug(5700) << "nickName differs";
233 return false;
234 }
235
236 if ( d->mBirthday != addressee.d->mBirthday ) {
237 kDebug(5700) << "birthday differs";
238 return false;
239 }
240
241 if ( d->mMailer != addressee.d->mMailer &&
242 !( d->mMailer.isEmpty() && addressee.d->mMailer.isEmpty() ) ) {
243 kDebug(5700) << "mailer differs";
244 return false;
245 }
246
247 if ( d->mTimeZone != addressee.d->mTimeZone ) {
248 kDebug(5700) << "timeZone differs";
249 return false;
250 }
251
252 if ( d->mGeo != addressee.d->mGeo ) {
253 kDebug(5700) << "geo differs";
254 return false;
255 }
256
257 if ( d->mTitle != addressee.d->mTitle &&
258 !( d->mTitle.isEmpty() && addressee.d->mTitle.isEmpty() ) ) {
259 kDebug(5700) << "title differs";
260 return false;
261 }
262
263 if ( d->mRole != addressee.d->mRole &&
264 !( d->mRole.isEmpty() && addressee.d->mRole.isEmpty() ) ) {
265 kDebug(5700) << "role differs";
266 return false;
267 }
268
269 if ( d->mOrganization != addressee.d->mOrganization &&
270 !( d->mOrganization.isEmpty() && addressee.d->mOrganization.isEmpty() ) ) {
271 kDebug(5700) << "organization differs";
272 return false;
273 }
274
275 if ( d->mDepartment != addressee.d->mDepartment &&
276 !( d->mDepartment.isEmpty() && addressee.d->mDepartment.isEmpty() ) ) {
277 kDebug(5700) << "department differs";
278 return false;
279 }
280
281 if ( d->mNote != addressee.d->mNote &&
282 !( d->mNote.isEmpty() && addressee.d->mNote.isEmpty() ) ) {
283 kDebug(5700) << "note differs";
284 return false;
285 }
286
287 if ( d->mProductId != addressee.d->mProductId &&
288 !( d->mProductId.isEmpty() && addressee.d->mProductId.isEmpty() ) ) {
289 kDebug(5700) << "productId differs";
290 return false;
291 }
292
293 if ( d->mSortString != addressee.d->mSortString &&
294 !( d->mSortString.isEmpty() && addressee.d->mSortString.isEmpty() ) ) {
295 kDebug(5700) << "sortString differs";
296 return false;
297 }
298
299 if ( d->mSecrecy != addressee.d->mSecrecy ) {
300 kDebug(5700) << "secrecy differs";
301 return false;
302 }
303
304 if ( d->mLogo != addressee.d->mLogo ) {
305 kDebug(5700) << "logo differs";
306 return false;
307 }
308
309 if ( d->mPhoto != addressee.d->mPhoto ) {
310 kDebug(5700) << "photo differs";
311 return false;
312 }
313
314 if ( d->mSound != addressee.d->mSound ) {
315 kDebug(5700) << "sound differs";
316 return false;
317 }
318
319 if ( ( d->mUrl.isValid() || addressee.d->mUrl.isValid() ) &&
320 ( d->mUrl != addressee.d->mUrl ) ) {
321 kDebug() << "url differs";
322 return false;
323 }
324
325 if ( !listEquals( d->mPhoneNumbers, addressee.d->mPhoneNumbers ) ) {
326 kDebug() << "phoneNumbers differs";
327 return false;
328 }
329
330 if ( !listEquals( d->mAddresses, addressee.d->mAddresses ) ) {
331 kDebug() << "addresses differs";
332 return false;
333 }
334
335 if ( !listEquals( d->mKeys, addressee.d->mKeys ) ) {
336 kDebug() << "keys differs";
337 return false;
338 }
339
340 if ( !emailsEquals( d->mEmails, addressee.d->mEmails ) ) {
341 kDebug() << "emails differs";
342 return false;
343 }
344
345 if ( !listEquals( d->mCategories, addressee.d->mCategories ) ) {
346 kDebug() << "categories differs";
347 return false;
348 }
349
350 if ( d->mCustomFields != addressee.d->mCustomFields ) {
351 kDebug() << "custom differs";
352 return false;
353 }
354
355 return true;
356}
357
358bool Addressee::operator!=( const Addressee &a ) const
359{
360 return !( a == *this );
361}
362
363bool Addressee::isEmpty() const
364{
365 return d->mEmpty;
366}
367
368void Addressee::setUid( const QString &id )
369{
370 if ( id == d->mUid )
371 return;
372
373 d->mEmpty = false;
374 d->mUid = id;
375}
376
377QString Addressee::uid() const
378{
379 return d->mUid;
380}
381
382QString Addressee::uidLabel()
383{
384 return i18n( "Unique Identifier" );
385}
386
387void Addressee::setName( const QString &name )
388{
389 if ( name == d->mName )
390 return;
391
392 d->mEmpty = false;
393 d->mName = name;
394}
395
396QString Addressee::name() const
397{
398 return d->mName;
399}
400
401QString Addressee::nameLabel()
402{
403 return i18n( "Name" );
404}
405
406
407void Addressee::setFormattedName( const QString &formattedName )
408{
409 if ( formattedName == d->mFormattedName )
410 return;
411
412 d->mEmpty = false;
413 d->mFormattedName = formattedName;
414}
415
416QString Addressee::formattedName() const
417{
418 return d->mFormattedName;
419}
420
421QString Addressee::formattedNameLabel()
422{
423 return i18n( "Formatted Name" );
424}
425
426
427void Addressee::setFamilyName( const QString &familyName )
428{
429 if ( familyName == d->mFamilyName )
430 return;
431
432 d->mEmpty = false;
433 d->mFamilyName = familyName;
434}
435
436QString Addressee::familyName() const
437{
438 return d->mFamilyName;
439}
440
441QString Addressee::familyNameLabel()
442{
443 return i18n( "Family Name" );
444}
445
446
447void Addressee::setGivenName( const QString &givenName )
448{
449 if ( givenName == d->mGivenName )
450 return;
451
452 d->mEmpty = false;
453 d->mGivenName = givenName;
454}
455
456QString Addressee::givenName() const
457{
458 return d->mGivenName;
459}
460
461QString Addressee::givenNameLabel()
462{
463 return i18n( "Given Name" );
464}
465
466
467void Addressee::setAdditionalName( const QString &additionalName )
468{
469 if ( additionalName == d->mAdditionalName )
470 return;
471
472 d->mEmpty = false;
473 d->mAdditionalName = additionalName;
474}
475
476QString Addressee::additionalName() const
477{
478 return d->mAdditionalName;
479}
480
481QString Addressee::additionalNameLabel()
482{
483 return i18n( "Additional Names" );
484}
485
486
487void Addressee::setPrefix( const QString &prefix )
488{
489 if ( prefix == d->mPrefix )
490 return;
491
492 d->mEmpty = false;
493 d->mPrefix = prefix;
494}
495
496QString Addressee::prefix() const
497{
498 return d->mPrefix;
499}
500
501QString Addressee::prefixLabel()
502{
503 return i18n( "Honorific Prefixes" );
504}
505
506
507void Addressee::setSuffix( const QString &suffix )
508{
509 if ( suffix == d->mSuffix )
510 return;
511
512 d->mEmpty = false;
513 d->mSuffix = suffix;
514}
515
516QString Addressee::suffix() const
517{
518 return d->mSuffix;
519}
520
521QString Addressee::suffixLabel()
522{
523 return i18n( "Honorific Suffixes" );
524}
525
526
527void Addressee::setNickName( const QString &nickName )
528{
529 if ( nickName == d->mNickName )
530 return;
531
532 d->mEmpty = false;
533 d->mNickName = nickName;
534}
535
536QString Addressee::nickName() const
537{
538 return d->mNickName;
539}
540
541QString Addressee::nickNameLabel()
542{
543 return i18n( "Nick Name" );
544}
545
546
547void Addressee::setBirthday( const QDateTime &birthday )
548{
549 if ( birthday == d->mBirthday )
550 return;
551
552 d->mEmpty = false;
553 d->mBirthday = birthday;
554}
555
556QDateTime Addressee::birthday() const
557{
558 return d->mBirthday;
559}
560
561QString Addressee::birthdayLabel()
562{
563 return i18n( "Birthday" );
564}
565
566
567QString Addressee::homeAddressStreetLabel()
568{
569 return i18n( "Home Address Street" );
570}
571
572
573QString Addressee::homeAddressPostOfficeBoxLabel()
574{
575 return i18n( "Home Address Post Office Box" );
576}
577
578
579QString Addressee::homeAddressLocalityLabel()
580{
581 return i18n( "Home Address City" );
582}
583
584
585QString Addressee::homeAddressRegionLabel()
586{
587 return i18n( "Home Address State" );
588}
589
590
591QString Addressee::homeAddressPostalCodeLabel()
592{
593 return i18n( "Home Address Zip Code" );
594}
595
596
597QString Addressee::homeAddressCountryLabel()
598{
599 return i18n( "Home Address Country" );
600}
601
602
603QString Addressee::homeAddressLabelLabel()
604{
605 return i18n( "Home Address Label" );
606}
607
608
609QString Addressee::businessAddressStreetLabel()
610{
611 return i18n( "Business Address Street" );
612}
613
614
615QString Addressee::businessAddressPostOfficeBoxLabel()
616{
617 return i18n( "Business Address Post Office Box" );
618}
619
620
621QString Addressee::businessAddressLocalityLabel()
622{
623 return i18n( "Business Address City" );
624}
625
626
627QString Addressee::businessAddressRegionLabel()
628{
629 return i18n( "Business Address State" );
630}
631
632
633QString Addressee::businessAddressPostalCodeLabel()
634{
635 return i18n( "Business Address Zip Code" );
636}
637
638
639QString Addressee::businessAddressCountryLabel()
640{
641 return i18n( "Business Address Country" );
642}
643
644
645QString Addressee::businessAddressLabelLabel()
646{
647 return i18n( "Business Address Label" );
648}
649
650
651QString Addressee::homePhoneLabel()
652{
653 return i18n( "Home Phone" );
654}
655
656
657QString Addressee::businessPhoneLabel()
658{
659 return i18n( "Business Phone" );
660}
661
662
663QString Addressee::mobilePhoneLabel()
664{
665 return i18n( "Mobile Phone" );
666}
667
668
669QString Addressee::homeFaxLabel()
670{
671 return i18n( "Home Fax" );
672}
673
674
675QString Addressee::businessFaxLabel()
676{
677 return i18n( "Business Fax" );
678}
679
680
681QString Addressee::carPhoneLabel()
682{
683 return i18n( "Car Phone" );
684}
685
686
687QString Addressee::isdnLabel()
688{
689 return i18n( "ISDN" );
690}
691
692
693QString Addressee::pagerLabel()
694{
695 return i18n( "Pager" );
696}
697
698
699QString Addressee::emailLabel()
700{
701 return i18n( "Email Address" );
702}
703
704
705void Addressee::setMailer( const QString &mailer )
706{
707 if ( mailer == d->mMailer )
708 return;
709
710 d->mEmpty = false;
711 d->mMailer = mailer;
712}
713
714QString Addressee::mailer() const
715{
716 return d->mMailer;
717}
718
719QString Addressee::mailerLabel()
720{
721 return i18n( "Mail Client" );
722}
723
724
725void Addressee::setTimeZone( const TimeZone &timeZone )
726{
727 if ( timeZone == d->mTimeZone )
728 return;
729
730 d->mEmpty = false;
731 d->mTimeZone = timeZone;
732}
733
734TimeZone Addressee::timeZone() const
735{
736 return d->mTimeZone;
737}
738
739QString Addressee::timeZoneLabel()
740{
741 return i18n( "Time Zone" );
742}
743
744
745void Addressee::setGeo( const Geo &geo )
746{
747 if ( geo == d->mGeo )
748 return;
749
750 d->mEmpty = false;
751 d->mGeo = geo;
752}
753
754Geo Addressee::geo() const
755{
756 return d->mGeo;
757}
758
759QString Addressee::geoLabel()
760{
761 return i18n( "Geographic Position" );
762}
763
764
765void Addressee::setTitle( const QString &title )
766{
767 if ( title == d->mTitle )
768 return;
769
770 d->mEmpty = false;
771 d->mTitle = title;
772}
773
774QString Addressee::title() const
775{
776 return d->mTitle;
777}
778
779QString Addressee::titleLabel()
780{
781 return i18nc( "a person's title", "Title" );
782}
783
784
785void Addressee::setRole( const QString &role )
786{
787 if ( role == d->mRole )
788 return;
789
790 d->mEmpty = false;
791 d->mRole = role;
792}
793
794QString Addressee::role() const
795{
796 return d->mRole;
797}
798
799QString Addressee::roleLabel()
800{
801 return i18nc( "of a person in an organization", "Role" );
802}
803
804
805void Addressee::setOrganization( const QString &organization )
806{
807 if ( organization == d->mOrganization )
808 return;
809
810 d->mEmpty = false;
811 d->mOrganization = organization;
812}
813
814QString Addressee::organization() const
815{
816 return d->mOrganization;
817}
818
819QString Addressee::organizationLabel()
820{
821 return i18n( "Organization" );
822}
823
824
825void Addressee::setDepartment( const QString &department )
826{
827 if ( department == d->mDepartment )
828 return;
829
830 d->mEmpty = false;
831 d->mDepartment = department;
832}
833
834QString Addressee::department() const
835{
836 return d->mDepartment;
837}
838
839QString Addressee::departmentLabel()
840{
841 return i18n( "Department" );
842}
843
844
845void Addressee::setNote( const QString &note )
846{
847 if ( note == d->mNote )
848 return;
849
850 d->mEmpty = false;
851 d->mNote = note;
852}
853
854QString Addressee::note() const
855{
856 return d->mNote;
857}
858
859QString Addressee::noteLabel()
860{
861 return i18n( "Note" );
862}
863
864
865void Addressee::setProductId( const QString &productId )
866{
867 if ( productId == d->mProductId )
868 return;
869
870 d->mEmpty = false;
871 d->mProductId = productId;
872}
873
874QString Addressee::productId() const
875{
876 return d->mProductId;
877}
878
879QString Addressee::productIdLabel()
880{
881 return i18n( "Product Identifier" );
882}
883
884
885void Addressee::setRevision( const QDateTime &revision )
886{
887 if ( revision == d->mRevision )
888 return;
889
890 d->mEmpty = false;
891 d->mRevision = revision;
892}
893
894QDateTime Addressee::revision() const
895{
896 return d->mRevision;
897}
898
899QString Addressee::revisionLabel()
900{
901 return i18n( "Revision Date" );
902}
903
904
905void Addressee::setSortString( const QString &sortString )
906{
907 if ( sortString == d->mSortString )
908 return;
909
910 d->mEmpty = false;
911 d->mSortString = sortString;
912}
913
914QString Addressee::sortString() const
915{
916 return d->mSortString;
917}
918
919QString Addressee::sortStringLabel()
920{
921 return i18n( "Sort String" );
922}
923
924
925void Addressee::setUrl( const KUrl &url )
926{
927 if ( url == d->mUrl )
928 return;
929
930 d->mEmpty = false;
931 d->mUrl = url;
932}
933
934KUrl Addressee::url() const
935{
936 return d->mUrl;
937}
938
939QString Addressee::urlLabel()
940{
941 return i18n( "Homepage" );
942}
943
944
945void Addressee::setSecrecy( const Secrecy &secrecy )
946{
947 if ( secrecy == d->mSecrecy )
948 return;
949
950 d->mEmpty = false;
951 d->mSecrecy = secrecy;
952}
953
954Secrecy Addressee::secrecy() const
955{
956 return d->mSecrecy;
957}
958
959QString Addressee::secrecyLabel()
960{
961 return i18n( "Security Class" );
962}
963
964
965void Addressee::setLogo( const Picture & )
966{
967 if ( logo == d->mLogo )
968 return;
969
970 d->mEmpty = false;
971 d->mLogo = logo;
972}
973
974Picture Addressee::logo() const
975{
976 return d->mLogo;
977}
978
979QString Addressee::logoLabel()
980{
981 return i18n( "Logo" );
982}
983
984
985void Addressee::setPhoto( const Picture &photo )
986{
987 if ( photo == d->mPhoto )
988 return;
989
990 d->mEmpty = false;
991 d->mPhoto = photo;
992}
993
994Picture Addressee::photo() const
995{
996 return d->mPhoto;
997}
998
999QString Addressee::photoLabel()
1000{
1001 return i18n( "Photo" );
1002}
1003
1004
1005void Addressee::setSound( const Sound &sound )
1006{
1007 if ( sound == d->mSound )
1008 return;
1009
1010 d->mEmpty = false;
1011 d->mSound = sound;
1012}
1013
1014Sound Addressee::sound() const
1015{
1016 return d->mSound;
1017}
1018
1019QString Addressee::soundLabel()
1020{
1021 return i18n( "Sound" );
1022}
1023
1024
1025void Addressee::setNameFromString( const QString &s )
1026{
1027 QString str = s;
1028 //remove enclosing quotes from string
1029 if ( str.length() > 1 &&
1030 s[ 0 ] == QLatin1Char( '"' ) &&
1031 s[ s.length() - 1 ] == QLatin1Char( '"' ) ) {
1032 str = s.mid( 1, s.length() - 2 );
1033 }
1034
1035 setFormattedName( str );
1036 setName( str );
1037
1038 // clear all name parts
1039 setPrefix( QString() );
1040 setGivenName( QString() );
1041 setAdditionalName( QString() );
1042 setFamilyName( QString() );
1043 setSuffix( QString() );
1044
1045 if ( str.isEmpty() )
1046 return;
1047
1048 static QString spaceStr = QString::fromLatin1( " " );
1049 static QString emptyStr = QString::fromLatin1( "" );
1050 AddresseeHelper *helper = AddresseeHelper::self();
1051
1052 int i = str.indexOf( QLatin1Char( ',' ) );
1053 if ( i < 0 ) {
1054 QStringList parts = str.split( spaceStr );
1055 int leftOffset = 0;
1056 int rightOffset = parts.count() - 1;
1057
1058 QString suffix;
1059 while ( rightOffset >= 0 ) {
1060 if ( helper->containsSuffix( parts[ rightOffset ] ) ) {
1061 suffix.prepend( parts[ rightOffset ] + ( suffix.isEmpty() ? emptyStr : spaceStr ) );
1062 rightOffset--;
1063 } else
1064 break;
1065 }
1066 setSuffix( suffix );
1067
1068 if ( rightOffset < 0 )
1069 return;
1070
1071 if ( rightOffset - 1 >= 0 && helper->containsPrefix( parts[ rightOffset - 1 ].toLower() ) ) {
1072 setFamilyName( parts[ rightOffset - 1 ] + spaceStr + parts[ rightOffset ] );
1073 rightOffset--;
1074 } else {
1075 if ( helper->tradeAsFamilyName() )
1076 setFamilyName( parts[ rightOffset ] );
1077 else
1078 setGivenName( parts[ rightOffset ] );
1079 }
1080
1081 QString prefix;
1082 while ( leftOffset < rightOffset ) {
1083 if ( helper->containsTitle( parts[ leftOffset ] ) ) {
1084 prefix.append( ( prefix.isEmpty() ? emptyStr : spaceStr ) + parts[ leftOffset ] );
1085 leftOffset++;
1086 } else
1087 break;
1088 }
1089 setPrefix( prefix );
1090
1091 if ( leftOffset < rightOffset ) {
1092 setGivenName( parts[ leftOffset ] );
1093 leftOffset++;
1094 }
1095
1096 QString additionalName;
1097 while ( leftOffset < rightOffset ) {
1098 additionalName.append( ( additionalName.isEmpty() ? emptyStr : spaceStr ) + parts[ leftOffset ] );
1099 leftOffset++;
1100 }
1101 setAdditionalName( additionalName );
1102 } else {
1103 QString part1 = str.left( i );
1104 QString part2 = str.mid( i + 1 );
1105
1106 QStringList parts = part1.split( spaceStr );
1107 int leftOffset = 0;
1108 int rightOffset = parts.count() - 1;
1109
1110 if ( parts.count() > 0 ) {
1111
1112 QString suffix;
1113 while ( rightOffset >= 0 ) {
1114 if ( helper->containsSuffix( parts[ rightOffset ] ) ) {
1115 suffix.prepend( parts[ rightOffset ] + ( suffix.isEmpty() ? emptyStr : spaceStr ) );
1116 rightOffset--;
1117 } else
1118 break;
1119 }
1120 setSuffix( suffix );
1121
1122 if ( rightOffset - 1 >= 0 && helper->containsPrefix( parts[ rightOffset - 1 ].toLower() ) ) {
1123 setFamilyName( parts[ rightOffset - 1 ] + spaceStr + parts[ rightOffset ] );
1124 rightOffset--;
1125 } else
1126 setFamilyName( parts[ rightOffset ] );
1127
1128 QString prefix;
1129 while ( leftOffset < rightOffset ) {
1130 if ( helper->containsTitle( parts[ leftOffset ] ) ) {
1131 prefix.append( ( prefix.isEmpty() ? emptyStr : spaceStr ) + parts[ leftOffset ] );
1132 leftOffset++;
1133 } else
1134 break;
1135 }
1136 } else {
1137 setPrefix( QString() );
1138 setFamilyName( QString() );
1139 setSuffix( QString() );
1140 }
1141
1142 parts = part2.split( spaceStr );
1143
1144 leftOffset = 0;
1145 rightOffset = parts.count();
1146
1147 if ( parts.count() > 0 ) {
1148
1149 QString prefix;
1150 while ( leftOffset < rightOffset ) {
1151 if ( helper->containsTitle( parts[ leftOffset ] ) ) {
1152 prefix.append( ( prefix.isEmpty() ? emptyStr : spaceStr ) + parts[ leftOffset ] );
1153 leftOffset++;
1154 } else
1155 break;
1156 }
1157 setPrefix( prefix );
1158
1159 if ( leftOffset < rightOffset ) {
1160 setGivenName( parts[ leftOffset ] );
1161 leftOffset++;
1162 }
1163
1164 QString additionalName;
1165 while ( leftOffset < rightOffset ) {
1166 additionalName.append( ( additionalName.isEmpty() ? emptyStr : spaceStr ) + parts[ leftOffset ] );
1167 leftOffset++;
1168 }
1169 setAdditionalName( additionalName );
1170 } else {
1171 setGivenName( QString() );
1172 setAdditionalName( QString() );
1173 }
1174 }
1175}
1176
1177QString Addressee::realName() const
1178{
1179 QString n( formattedName() );
1180 if ( !n.isEmpty() )
1181 return n;
1182
1183 n = assembledName();
1184 if ( !n.isEmpty() )
1185 return n;
1186
1187 n = name();
1188 if ( !n.isEmpty() )
1189 return n;
1190
1191 return organization();
1192}
1193
1194QString Addressee::assembledName() const
1195{
1196 const QString name = prefix() + QLatin1Char( ' ' ) +
1197 givenName() + QLatin1Char( ' ' ) +
1198 additionalName() + QLatin1Char( ' ' ) +
1199 familyName() + QLatin1Char( ' ' ) +
1200 suffix();
1201
1202 return name.simplified();
1203}
1204
1205QString Addressee::fullEmail( const QString &email ) const
1206{
1207 QString e;
1208 if ( email.isNull() ) {
1209 e = preferredEmail();
1210 } else {
1211 e = email;
1212 }
1213 if ( e.isEmpty() ) return QString();
1214
1215 QString text;
1216 if ( realName().isEmpty() )
1217 text = e;
1218 else {
1219 QRegExp needQuotes( QLatin1String( "[^ 0-9A-Za-z\\x0080-\\xFFFF]" ) );
1220 if ( realName().indexOf( needQuotes ) != -1 ) {
1221 QString name = realName();
1222 name.replace( QLatin1String( "\"" ), QLatin1String( "\\\"" ) );
1223 text = QLatin1String( "\"" ) + name + QLatin1String( "\" <" ) + e + QLatin1Char( '>' );
1224 } else
1225 text = realName() + QLatin1String( " <" ) + e + QLatin1Char( '>' );
1226 }
1227
1228 return text;
1229}
1230
1231void Addressee::insertEmail( const QString &email, bool preferred )
1232{
1233 if ( email.simplified().isEmpty() )
1234 return;
1235
1236 if ( d->mEmails.contains( email ) ) {
1237 if ( !preferred || d->mEmails.first() == email )
1238 return;
1239
1240 d->mEmails.removeAll( email );
1241 d->mEmails.prepend( email );
1242 } else {
1243 d->mEmpty = false;
1244 if ( preferred ) {
1245 d->mEmails.prepend( email );
1246 } else {
1247 d->mEmails.append( email );
1248 }
1249 }
1250}
1251
1252void Addressee::removeEmail( const QString &email )
1253{
1254 if ( d->mEmails.contains( email ) ) {
1255 d->mEmails.removeAll( email );
1256 }
1257}
1258
1259QString Addressee::preferredEmail() const
1260{
1261 if ( d->mEmails.count() == 0 )
1262 return QString();
1263 else
1264 return d->mEmails.first();
1265}
1266
1267QStringList Addressee::emails() const
1268{
1269 return d->mEmails;
1270}
1271
1272void Addressee::setEmails( const QStringList& emails )
1273{
1274 d->mEmails = emails;
1275}
1276void Addressee::insertPhoneNumber( const PhoneNumber &phoneNumber )
1277{
1278 d->mEmpty = false;
1279
1280 PhoneNumber::List::Iterator it;
1281 for ( it = d->mPhoneNumbers.begin(); it != d->mPhoneNumbers.end(); ++it ) {
1282 if ( ( *it ).id() == phoneNumber.id() ) {
1283 *it = phoneNumber;
1284 return;
1285 }
1286 }
1287 if ( !phoneNumber.number().simplified().isEmpty() )
1288 d->mPhoneNumbers.append( phoneNumber );
1289}
1290
1291void Addressee::removePhoneNumber( const PhoneNumber &phoneNumber )
1292{
1293 PhoneNumber::List::Iterator it;
1294 for ( it = d->mPhoneNumbers.begin(); it != d->mPhoneNumbers.end(); ++it ) {
1295 if ( ( *it ).id() == phoneNumber.id() ) {
1296 d->mPhoneNumbers.erase( it );
1297 return;
1298 }
1299 }
1300}
1301
1302PhoneNumber Addressee::phoneNumber( PhoneNumber::Type type ) const
1303{
1304 PhoneNumber phoneNumber( QString(), type );
1305 PhoneNumber::List::ConstIterator it;
1306 for ( it = d->mPhoneNumbers.constBegin(); it != d->mPhoneNumbers.constEnd(); ++it ) {
1307 if ( matchBinaryPattern( ( *it ).type(), type ) ) {
1308 if ( ( *it ).type() & PhoneNumber::Pref ) {
1309 return ( *it );
1310 } else if ( phoneNumber.number().isEmpty() ) {
1311 phoneNumber = ( *it );
1312 }
1313 }
1314 }
1315
1316 return phoneNumber;
1317}
1318
1319PhoneNumber::List Addressee::phoneNumbers() const
1320{
1321 return d->mPhoneNumbers;
1322}
1323
1324PhoneNumber::List Addressee::phoneNumbers( PhoneNumber::Type type ) const
1325{
1326 PhoneNumber::List list;
1327
1328 PhoneNumber::List::ConstIterator it;
1329 PhoneNumber::List::ConstIterator end( d->mPhoneNumbers.constEnd() );
1330 for ( it = d->mPhoneNumbers.constBegin(); it != end; ++it ) {
1331 if ( matchBinaryPattern( ( *it ).type(), type ) ) {
1332 list.append( *it );
1333 }
1334 }
1335 return list;
1336}
1337
1338PhoneNumber Addressee::findPhoneNumber( const QString &id ) const
1339{
1340 PhoneNumber::List::ConstIterator it;
1341 PhoneNumber::List::ConstIterator end( d->mPhoneNumbers.constEnd() );
1342 for ( it = d->mPhoneNumbers.constBegin(); it != end; ++it ) {
1343 if ( ( *it ).id() == id ) {
1344 return *it;
1345 }
1346 }
1347 return PhoneNumber();
1348}
1349
1350void Addressee::insertKey( const Key &key )
1351{
1352 d->mEmpty = false;
1353
1354 Key::List::Iterator it;
1355 for ( it = d->mKeys.begin(); it != d->mKeys.end(); ++it ) {
1356 if ( ( *it ).id() == key.id() ) {
1357 *it = key;
1358 return;
1359 }
1360 }
1361 d->mKeys.append( key );
1362}
1363
1364void Addressee::removeKey( const Key &key )
1365{
1366 Key::List::Iterator it;
1367 for ( it = d->mKeys.begin(); it != d->mKeys.end(); ++it ) {
1368 if ( ( *it ).id() == key.id() ) {
1369 d->mKeys.removeAll( key );
1370 return;
1371 }
1372 }
1373}
1374
1375Key Addressee::key( Key::Type type, QString customTypeString ) const
1376{
1377 Key::List::ConstIterator it;
1378 Key::List::ConstIterator end( d->mKeys.constEnd() );
1379 for ( it = d->mKeys.constBegin(); it != end; ++it ) {
1380 if ( ( *it ).type() == type ) {
1381 if ( type == Key::Custom ) {
1382 if ( customTypeString.isEmpty() ) {
1383 return *it;
1384 } else {
1385 if ( ( *it ).customTypeString() == customTypeString )
1386 return ( *it );
1387 }
1388 } else {
1389 return *it;
1390 }
1391 }
1392 }
1393 return Key( QString(), type );
1394}
1395
1396void Addressee::setKeys( const Key::List& list )
1397{
1398 d->mKeys = list;
1399}
1400
1401Key::List Addressee::keys() const
1402{
1403 return d->mKeys;
1404}
1405
1406Key::List Addressee::keys( Key::Type type, QString customTypeString ) const
1407{
1408 Key::List list;
1409
1410 Key::List::ConstIterator it;
1411 Key::List::ConstIterator end( d->mKeys.constEnd() );
1412 for ( it = d->mKeys.constBegin(); it != end; ++it ) {
1413 if ( ( *it ).type() == type ) {
1414 if ( type == Key::Custom ) {
1415 if ( customTypeString.isEmpty() ) {
1416 list.append( *it );
1417 } else {
1418 if ( ( *it ).customTypeString() == customTypeString )
1419 list.append( *it );
1420 }
1421 } else {
1422 list.append( *it );
1423 }
1424 }
1425 }
1426 return list;
1427}
1428
1429Key Addressee::findKey( const QString &id ) const
1430{
1431 Key::List::ConstIterator it;
1432 Key::List::ConstIterator end( d->mKeys.constEnd() );
1433 for ( it = d->mKeys.constBegin(); it != end; ++it ) {
1434 if ( ( *it ).id() == id ) {
1435 return *it;
1436 }
1437 }
1438 return Key();
1439}
1440
1441QString Addressee::toString() const
1442{
1443 QString str;
1444
1445 str += QLatin1String( "Addressee {\n" );
1446 str += QString::fromLatin1( " Uid: %1\n" ).arg( uid() );
1447
1448 str += QString::fromLatin1( " Name: %1\n" ).arg( name() );
1449 str += QString::fromLatin1( " FormattedName: %1\n" ).arg( formattedName() );
1450 str += QString::fromLatin1( " FamilyName: %1\n" ).arg( familyName() );
1451 str += QString::fromLatin1( " GivenName: %1\n" ).arg( givenName() );
1452 str += QString::fromLatin1( " AdditionalName: %1\n" ).arg( additionalName() );
1453 str += QString::fromLatin1( " Prefix: %1\n" ).arg( prefix() );
1454 str += QString::fromLatin1( " Suffix: %1\n" ).arg( suffix() );
1455 str += QString::fromLatin1( " NickName: %1\n" ).arg( nickName() );
1456 str += QString::fromLatin1( " Birthday: %1\n" ).arg( birthday().toString() );
1457 str += QString::fromLatin1( " Mailer: %1\n" ).arg( mailer() );
1458 str += QString::fromLatin1( " TimeZone: %1\n" ).arg( timeZone().toString() );
1459 str += QString::fromLatin1( " Geo: %1\n" ).arg( geo().toString() );
1460 str += QString::fromLatin1( " Title: %1\n" ).arg( title() );
1461 str += QString::fromLatin1( " Role: %1\n" ).arg( role() );
1462 str += QString::fromLatin1( " Organization: %1\n" ).arg( organization() );
1463 str += QString::fromLatin1( " Department: %1\n" ).arg( department() );
1464 str += QString::fromLatin1( " Note: %1\n" ).arg( note() );
1465 str += QString::fromLatin1( " ProductId: %1\n" ).arg( productId() );
1466 str += QString::fromLatin1( " Revision: %1\n" ).arg( revision().toString() );
1467 str += QString::fromLatin1( " SortString: %1\n" ).arg( sortString() );
1468 str += QString::fromLatin1( " Url: %1\n" ).arg( url().url() );
1469 str += QString::fromLatin1( " Secrecy: %1\n" ).arg( secrecy().toString() );
1470 str += QString::fromLatin1( " Logo: %1\n" ).arg( logo().toString() );
1471 str += QString::fromLatin1( " Photo: %1\n" ).arg( photo().toString() );
1472 str += QString::fromLatin1( " Sound: %1\n" ).arg( sound().toString() );
1473
1474 str += QLatin1String( " Emails {\n" );
1475 const QStringList e = emails();
1476 QStringList::ConstIterator it;
1477 for ( it = e.begin(); it != e.end(); ++it ) {
1478 str += QString::fromLatin1( " %1\n" ).arg( *it );
1479 }
1480 str += QLatin1String( " }\n" );
1481
1482 str += QLatin1String( " PhoneNumbers {\n" );
1483 const PhoneNumber::List p = phoneNumbers();
1484 PhoneNumber::List::ConstIterator it2;
1485 for ( it2 = p.begin(); it2 != p.end(); ++it2 ) {
1486 str += ( *it2 ).toString();
1487 }
1488 str += QLatin1String( " }\n" );
1489
1490 str += QLatin1String( " Addresses {\n" );
1491 const Address::List a = addresses();
1492 Address::List::ConstIterator it3;
1493 for ( it3 = a.begin(); it3 != a.end(); ++it3 ) {
1494 str += ( *it3 ).toString();
1495 }
1496 str += QLatin1String( " }\n" );
1497
1498 str += QLatin1String( " Keys {\n" );
1499 const Key::List k = keys();
1500 Key::List::ConstIterator it4;
1501 for ( it4 = k.begin(); it4 != k.end(); ++it4 ) {
1502 str += ( *it4 ).toString();
1503 }
1504 str += QLatin1String( " }\n" );
1505
1506 str += QLatin1String( "}\n" );
1507
1508 return str;
1509}
1510
1511
1512void Addressee::insertAddress( const Address &address )
1513{
1514 if ( address.isEmpty() )
1515 return;
1516
1517 d->mEmpty = false;
1518
1519 Address::List::Iterator it;
1520 for ( it = d->mAddresses.begin(); it != d->mAddresses.end(); ++it ) {
1521 if ( ( *it ).id() == address.id() ) {
1522 *it = address;
1523 return;
1524 }
1525 }
1526
1527 d->mAddresses.append( address );
1528}
1529
1530void Addressee::removeAddress( const Address &address )
1531{
1532 Address::List::Iterator it;
1533 for ( it = d->mAddresses.begin(); it != d->mAddresses.end(); ++it ) {
1534 if ( ( *it ).id() == address.id() ) {
1535 d->mAddresses.erase( it );
1536 return;
1537 }
1538 }
1539}
1540
1541Address Addressee::address( Address::Type type ) const
1542{
1543 Address address( type );
1544 Address::List::ConstIterator it;
1545 Address::List::ConstIterator end( d->mAddresses.constEnd() );
1546 for ( it = d->mAddresses.constBegin(); it != end; ++it ) {
1547 if ( matchBinaryPattern( ( *it ).type(), type ) ) {
1548 if ( ( *it ).type() & Address::Pref ) {
1549 return ( *it );
1550 } else if ( address.isEmpty() ) {
1551 address = ( *it );
1552 }
1553 }
1554 }
1555
1556 return address;
1557}
1558
1559Address::List Addressee::addresses() const
1560{
1561 return d->mAddresses;
1562}
1563
1564Address::List Addressee::addresses( Address::Type type ) const
1565{
1566 Address::List list;
1567
1568 Address::List::ConstIterator it;
1569 Address::List::ConstIterator end( d->mAddresses.constEnd() );
1570 for ( it = d->mAddresses.constBegin(); it != end; ++it ) {
1571 if ( matchBinaryPattern( ( *it ).type(), type ) ) {
1572 list.append( *it );
1573 }
1574 }
1575
1576 return list;
1577}
1578
1579Address Addressee::findAddress( const QString &id ) const
1580{
1581 Address::List::ConstIterator it;
1582 Address::List::ConstIterator end( d->mAddresses.constEnd() );
1583 for ( it = d->mAddresses.constBegin(); it != end; ++it ) {
1584 if ( ( *it ).id() == id ) {
1585 return *it;
1586 }
1587 }
1588 return Address();
1589}
1590
1591void Addressee::insertCategory( const QString &c )
1592{
1593 d->mEmpty = false;
1594
1595 if ( d->mCategories.contains( c ) )
1596 return;
1597
1598 d->mCategories.append( c );
1599}
1600
1601void Addressee::removeCategory( const QString &category )
1602{
1603 if ( d->mCategories.contains( category ) ) {
1604 d->mCategories.removeAll( category );
1605 }
1606}
1607
1608bool Addressee::hasCategory( const QString &category ) const
1609{
1610 return d->mCategories.contains( category );
1611}
1612
1613void Addressee::setCategories( const QStringList &c )
1614{
1615 d->mEmpty = false;
1616
1617 d->mCategories = c;
1618}
1619
1620QStringList Addressee::categories() const
1621{
1622 return d->mCategories;
1623}
1624
1625void Addressee::insertCustom( const QString &app, const QString &name,
1626 const QString &value )
1627{
1628 if ( value.isEmpty() || name.isEmpty() || app.isEmpty() ) {
1629 return;
1630 }
1631
1632 d->mEmpty = false;
1633
1634 const QString qualifiedName = app + QLatin1Char( '-' ) + name;
1635
1636 d->mCustomFields.insert( qualifiedName, value );
1637}
1638
1639void Addressee::removeCustom( const QString &app, const QString &name )
1640{
1641 const QString qualifiedName = app + QLatin1Char( '-' ) + name;
1642
1643 d->mCustomFields.remove( qualifiedName );
1644}
1645
1646QString Addressee::custom( const QString &app, const QString &name ) const
1647{
1648 const QString qualifiedName = app + QLatin1Char( '-' ) + name;
1649
1650 return d->mCustomFields.value( qualifiedName );
1651}
1652
1653void Addressee::setCustoms( const QStringList &customs )
1654{
1655 d->mEmpty = false;
1656
1657 d->mCustomFields.clear();
1658
1659 foreach ( const QString &custom, customs ) {
1660 const int index = custom.indexOf( QLatin1Char( ':' ) );
1661 if ( index == -1 )
1662 continue;
1663
1664 const QString qualifiedName = custom.left( index );
1665 const QString value = custom.mid( index + 1 );
1666
1667 d->mCustomFields.insert( qualifiedName, value );
1668 }
1669}
1670
1671QStringList Addressee::customs() const
1672{
1673 QStringList result;
1674
1675 QMapIterator<QString, QString> it( d->mCustomFields );
1676 while ( it.hasNext() ) {
1677 it.next();
1678 result << it.key() + QLatin1Char( ':' ) + it.value();
1679 }
1680
1681 return result;
1682}
1683
1684void Addressee::parseEmailAddress( const QString &rawEmail, QString &fullName,
1685 QString &email )
1686{
1687 // This is a simplified version of KPIM::splitAddress().
1688
1689 fullName.clear();
1690 email.clear();
1691 if ( rawEmail.isEmpty() )
1692 return; // KPIM::AddressEmpty;
1693
1694 // The code works on 8-bit strings, so convert the input to UTF-8.
1695 QByteArray address = rawEmail.toUtf8();
1696
1697 QByteArray displayName;
1698 QByteArray addrSpec;
1699 QByteArray comment;
1700
1701 // The following is a primitive parser for a mailbox-list (cf. RFC 2822).
1702 // The purpose is to extract a displayable string from the mailboxes.
1703 // Comments in the addr-spec are not handled. No error checking is done.
1704
1705 enum { TopLevel, InComment, InAngleAddress } context = TopLevel;
1706 bool inQuotedString = false;
1707 int commentLevel = 0;
1708 bool stop = false;
1709
1710 for ( char* p = address.data(); *p && !stop; ++p ) {
1711 switch ( context ) {
1712 case TopLevel : {
1713 switch ( *p ) {
1714 case '"' : inQuotedString = !inQuotedString;
1715 displayName += *p;
1716 break;
1717 case '(' : if ( !inQuotedString ) {
1718 context = InComment;
1719 commentLevel = 1;
1720 }
1721 else
1722 displayName += *p;
1723 break;
1724 case '<' : if ( !inQuotedString ) {
1725 context = InAngleAddress;
1726 }
1727 else
1728 displayName += *p;
1729 break;
1730 case '\\' : // quoted character
1731 displayName += *p;
1732 ++p; // skip the '\'
1733 if ( *p )
1734 displayName += *p;
1735 else
1736 //return KPIM::UnexpectedEnd;
1737 goto ABORT_PARSING;
1738 break;
1739 case ',' : if ( !inQuotedString ) {
1740 //if ( allowMultipleAddresses )
1741 // stop = true;
1742 //else
1743 // return KPIM::UnexpectedComma;
1744 goto ABORT_PARSING;
1745 }
1746 else
1747 displayName += *p;
1748 break;
1749 default : displayName += *p;
1750 }
1751 break;
1752 }
1753 case InComment : {
1754 switch ( *p ) {
1755 case '(' : ++commentLevel;
1756 comment += *p;
1757 break;
1758 case ')' : --commentLevel;
1759 if ( commentLevel == 0 ) {
1760 context = TopLevel;
1761 comment += ' '; // separate the text of several comments
1762 }
1763 else
1764 comment += *p;
1765 break;
1766 case '\\' : // quoted character
1767 comment += *p;
1768 ++p; // skip the '\'
1769 if ( *p )
1770 comment += *p;
1771 else
1772 //return KPIM::UnexpectedEnd;
1773 goto ABORT_PARSING;
1774 break;
1775 default : comment += *p;
1776 }
1777 break;
1778 }
1779 case InAngleAddress : {
1780 switch ( *p ) {
1781 case '"' : inQuotedString = !inQuotedString;
1782 addrSpec += *p;
1783 break;
1784 case '>' : if ( !inQuotedString ) {
1785 context = TopLevel;
1786 }
1787 else
1788 addrSpec += *p;
1789 break;
1790 case '\\' : // quoted character
1791 addrSpec += *p;
1792 ++p; // skip the '\'
1793 if ( *p )
1794 addrSpec += *p;
1795 else
1796 //return KPIM::UnexpectedEnd;
1797 goto ABORT_PARSING;
1798 break;
1799 default : addrSpec += *p;
1800 }
1801 break;
1802 }
1803 } // switch ( context )
1804 }
1805
1806ABORT_PARSING:
1807 displayName = displayName.trimmed();
1808 comment = comment.trimmed();
1809 addrSpec = addrSpec.trimmed();
1810
1811 fullName = QString::fromUtf8( displayName );
1812 email = QString::fromUtf8( addrSpec );
1813
1814 // check for errors
1815 if ( inQuotedString )
1816 return; // KPIM::UnbalancedQuote;
1817 if ( context == InComment )
1818 return; // KPIM::UnbalancedParens;
1819 if ( context == InAngleAddress )
1820 return; // KPIM::UnclosedAngleAddr;
1821
1822 if ( addrSpec.isEmpty() ) {
1823 if ( displayName.isEmpty() )
1824 return; // KPIM::NoAddressSpec;
1825 else {
1826 //addrSpec = displayName;
1827 //displayName.truncate( 0 );
1828 // Address of the form "foo@bar" or "foo@bar (Name)".
1829 email = fullName;
1830 fullName = QString::fromUtf8( comment );
1831 }
1832 }
1833
1834 email = email.toLower();
1835 // Check that we do not have any extra characters on the end of the
1836 // strings
1837 unsigned int len = fullName.length();
1838 if ( fullName[ 0 ] == QLatin1Char( '"' ) && fullName[ len - 1 ] == QLatin1Char( '"' ) ) {
1839 fullName = fullName.mid( 1, len - 2 );
1840 }
1841}
1842
1843#ifndef KDEPIM_NO_KRESOURCES
1844void Addressee::setResource( Resource *resource )
1845{
1846 d->mResource = resource;
1847}
1848
1849Resource *Addressee::resource() const
1850{
1851 return d->mResource;
1852}
1853#endif
1854
1855void Addressee::setChanged( bool value )
1856{
1857 d->mChanged = value;
1858}
1859
1860bool Addressee::changed() const
1861{
1862 return d->mChanged;
1863}
1864
1865void Addressee::setSortMode( KABC::SortMode *mode )
1866{
1867 Private::mSortMode = mode;
1868}
1869
1870bool Addressee::operator< ( const Addressee &addr ) const
1871{
1872 if ( !Private::mSortMode )
1873 return false;
1874 else
1875 return Private::mSortMode->lesser( *this, addr );
1876}
1877
1878QString Addressee::mimeType()
1879{
1880 return QLatin1String( "text/directory" );
1881}
1882
1883QDataStream &KABC::operator<<( QDataStream &s, const Addressee &a )
1884{
1885 s << a.d->mUid;
1886
1887 s << a.d->mName;
1888 s << a.d->mFormattedName;
1889 s << a.d->mFamilyName;
1890 s << a.d->mGivenName;
1891 s << a.d->mAdditionalName;
1892 s << a.d->mPrefix;
1893 s << a.d->mSuffix;
1894 s << a.d->mNickName;
1895 s << a.d->mBirthday;
1896 s << a.d->mMailer;
1897 s << a.d->mTimeZone;
1898 s << a.d->mGeo;
1899 s << a.d->mTitle;
1900 s << a.d->mRole;
1901 s << a.d->mOrganization;
1902 s << a.d->mDepartment;
1903 s << a.d->mNote;
1904 s << a.d->mProductId;
1905 s << a.d->mRevision;
1906 s << a.d->mSortString;
1907 s << a.d->mUrl;
1908 s << a.d->mSecrecy;
1909 s << a.d->mLogo;
1910 s << a.d->mPhoto;
1911 s << a.d->mSound;
1912 s << a.d->mPhoneNumbers;
1913 s << a.d->mAddresses;
1914 s << a.d->mEmails;
1915 s << a.d->mCategories;
1916 s << a.customs();
1917 s << a.d->mKeys;
1918 return s;
1919}
1920
1921QDataStream &KABC::operator>>( QDataStream &s, Addressee &a )
1922{
1923 s >> a.d->mUid;
1924
1925 s >> a.d->mName;
1926 s >> a.d->mFormattedName;
1927 s >> a.d->mFamilyName;
1928 s >> a.d->mGivenName;
1929 s >> a.d->mAdditionalName;
1930 s >> a.d->mPrefix;
1931 s >> a.d->mSuffix;
1932 s >> a.d->mNickName;
1933 s >> a.d->mBirthday;
1934 s >> a.d->mMailer;
1935 s >> a.d->mTimeZone;
1936 s >> a.d->mGeo;
1937 s >> a.d->mTitle;
1938 s >> a.d->mRole;
1939 s >> a.d->mOrganization;
1940 s >> a.d->mDepartment;
1941 s >> a.d->mNote;
1942 s >> a.d->mProductId;
1943 s >> a.d->mRevision;
1944 s >> a.d->mSortString;
1945 s >> a.d->mUrl;
1946 s >> a.d->mSecrecy;
1947 s >> a.d->mLogo;
1948 s >> a.d->mPhoto;
1949 s >> a.d->mSound;
1950 s >> a.d->mPhoneNumbers;
1951 s >> a.d->mAddresses;
1952 s >> a.d->mEmails;
1953 s >> a.d->mCategories;
1954 QStringList customFields;
1955 s >> customFields;
1956 a.setCustoms( customFields );
1957 s >> a.d->mKeys;
1958
1959 a.d->mEmpty = false;
1960
1961 return s;
1962}
1963
1964bool matchBinaryPattern( int value, int pattern )
1965{
1966 /**
1967 We want to match all telephonnumbers/addresses which have the bits in the
1968 pattern set. More are allowed.
1969 if pattern == 0 we have a special handling, then we want only those with
1970 exactly no bit set.
1971 */
1972 if ( pattern == 0 )
1973 return ( value == 0 );
1974 else
1975 return ( pattern == ( pattern & value ) );
1976}
1977
1978template <class L>
1979bool listEquals( const QList<L> &list, const QList<L> &pattern )
1980{
1981 if ( list.count() != pattern.count() )
1982 return false;
1983 const int numberOfElement( list.count() );
1984 for ( int i = 0; i < numberOfElement; ++i ) {
1985 if ( !pattern.contains( list[ i ] ) ) {
1986 return false;
1987 }
1988 }
1989
1990 return true;
1991}
1992
1993bool listEquals( const QStringList &list, const QStringList &pattern )
1994{
1995 if ( list.count() != pattern.count() )
1996 return false;
1997
1998 const int numberOfElement( list.count() );
1999 for ( int i = 0; i < numberOfElement; ++i ) {
2000 if ( !pattern.contains( list[ i ] ) ) {
2001 return false;
2002 }
2003 }
2004
2005 return true;
2006}
2007
2008bool emailsEquals( const QStringList &list, const QStringList &pattern )
2009{
2010 if ( list.count() != pattern.count() )
2011 return false;
2012
2013 if ( list.isEmpty() )
2014 return true;
2015
2016 if ( list.first() != pattern.first() )
2017 return false;
2018
2019 QStringList::ConstIterator it;
2020 QStringList::ConstIterator end( list.constEnd() );
2021 for ( it = list.constBegin(); it != end; ++it ) {
2022 if ( !pattern.contains( *it ) ) {
2023 return false;
2024 }
2025 }
2026
2027 return true;
2028}
2029