KContacts

vcardtool.cpp
1 /*
2  This file is part of the KContacts framework.
3  SPDX-FileCopyrightText: 2003 Tobias Koenig <[email protected]>
4  SPDX-FileCopyrightText: 2015-2019 Laurent Montel <[email protected]>
5 
6  SPDX-License-Identifier: LGPL-2.0-or-later
7 */
8 
9 #include "fieldgroup.h"
10 #include "gender.h"
11 #include "kcontacts_debug.h"
12 #include "key.h"
13 #include "lang.h"
14 #include "picture.h"
15 #include "related.h"
16 #include "secrecy.h"
17 #include "sound.h"
18 #include "vcardtool_p.h"
19 #include <QString>
20 
21 using namespace KContacts;
22 
23 static bool needsEncoding(const QString &value)
24 {
25  int length = value.length();
26  for (int i = 0; i < length; ++i) {
27  char c = value.at(i).toLatin1();
28  if ((c < 33 || c > 126) && c != ' ' && c != '=') {
29  return true;
30  }
31  }
32 
33  return false;
34 }
35 
36 static const struct {
37  const char *addressType;
38  Address::TypeFlag flag;
39 } s_addressTypes[] = {
40  {"dom", Address::Dom},
41  {"home", Address::Home},
42  {"intl", Address::Intl},
43  {"parcel", Address::Parcel},
44  {"postal", Address::Postal},
45  {"pref", Address::Pref},
46  {"work", Address::Work},
47 };
48 
49 static const unsigned int s_numAddressTypes = sizeof s_addressTypes / sizeof *s_addressTypes;
50 
51 static Address::TypeFlag stringToAddressType(const QString &str)
52 {
53  for (unsigned int i = 0; i < s_numAddressTypes; ++i) {
54  if (str == QLatin1String(s_addressTypes[i].addressType)) {
55  return s_addressTypes[i].flag;
56  }
57  }
58  return {};
59 }
60 
61 static const struct {
62  const char *phoneType;
64 } s_phoneTypes[] = {
65  {"BBS", PhoneNumber::Bbs},
66  {"CAR", PhoneNumber::Car},
67  {"CELL", PhoneNumber::Cell},
68  {"FAX", PhoneNumber::Fax},
69  {"HOME", PhoneNumber::Home},
70  {"ISDN", PhoneNumber::Isdn},
71  {"MODEM", PhoneNumber::Modem},
72  {"MSG", PhoneNumber::Msg},
73  {"PAGER", PhoneNumber::Pager},
74  {"PCS", PhoneNumber::Pcs},
75  {"PREF", PhoneNumber::Pref},
76  {"VIDEO", PhoneNumber::Video},
77  {"VOICE", PhoneNumber::Voice},
78  {"WORK", PhoneNumber::Work},
79 };
80 
81 static const unsigned int s_numPhoneTypes = sizeof s_phoneTypes / sizeof *s_phoneTypes;
82 
83 static PhoneNumber::TypeFlag stringToPhoneType(const QString &str)
84 {
85  for (unsigned int i = 0; i < s_numPhoneTypes; ++i) {
86  if (str == QLatin1String(s_phoneTypes[i].phoneType)) {
87  return s_phoneTypes[i].flag;
88  }
89  }
90  return {};
91 }
92 
93 VCardTool::VCardTool()
94 {
95 }
96 
97 VCardTool::~VCardTool()
98 {
99 }
100 
101 QByteArray VCardTool::exportVCards(const Addressee::List &list, VCard::Version version) const
102 {
103  return createVCards(list, version, true /*export vcard*/);
104 }
105 
106 QByteArray VCardTool::createVCards(const Addressee::List &list, VCard::Version version) const
107 {
108  return createVCards(list, version, false /*don't export*/);
109 }
110 
111 void VCardTool::addParameters(VCardLine &line, const QMap<QString, QStringList> &params) const
112 {
114  while (i.hasNext()) {
115  i.next();
116  line.addParameter(i.key(), i.value().join(QLatin1Char(',')));
117  }
118 }
119 
120 void VCardTool::addParameter(VCardLine &line, VCard::Version version, const QString &key, const QStringList &valueStringList) const
121 {
122  if (version == VCard::v2_1) {
123  for (const QString &valueStr : valueStringList) {
124  line.addParameter(valueStr, QString());
125  }
126  } else if (version == VCard::v3_0) {
127  line.addParameter(key, valueStringList.join(QLatin1Char(',')));
128  } else {
129  if (valueStringList.count() < 2) {
130  line.addParameter(key, valueStringList.join(QLatin1Char(',')));
131  } else {
132  line.addParameter(key, QLatin1Char('"') + valueStringList.join(QLatin1Char(',')) + QLatin1Char('"'));
133  }
134  }
135 }
136 
137 QByteArray VCardTool::createVCards(const Addressee::List &list, VCard::Version version, bool exportVcard) const
138 {
139  VCard::List vCardList;
140 
143  for (addrIt = list.constBegin(); addrIt != listEnd; ++addrIt) {
144  VCard card;
146  // VERSION
147  if (version == VCard::v2_1) {
148  card.addLine(VCardLine(QStringLiteral("VERSION"), QStringLiteral("2.1")));
149  } else if (version == VCard::v3_0) {
150  card.addLine(VCardLine(QStringLiteral("VERSION"), QStringLiteral("3.0")));
151  } else if (version == VCard::v4_0) {
152  card.addLine(VCardLine(QStringLiteral("VERSION"), QStringLiteral("4.0")));
153  }
154 
155  // ADR + LABEL
156  const Address::List addresses = (*addrIt).addresses();
157  Address::List::ConstIterator end(addresses.end());
158  for (Address::List::ConstIterator it = addresses.begin(); it != end; ++it) {
160 
161  // clang-format off
162  const bool isEmpty = ((*it).postOfficeBox().isEmpty()
163  && (*it).extended().isEmpty()
164  && (*it).street().isEmpty()
165  && (*it).locality().isEmpty()
166  && (*it).region().isEmpty()
167  && (*it).postalCode().isEmpty()
168  && (*it).country().isEmpty());
169 
170  address.append((*it).postOfficeBox().replace(QLatin1Char(';'),
171  QStringLiteral("\\;")));
172 
173  address.append((*it).extended().replace(QLatin1Char(';'),
174  QStringLiteral("\\;")));
175 
176  address.append((*it).street().replace(QLatin1Char(';'),
177  QStringLiteral("\\;")));
178 
179  address.append((*it).locality().replace(QLatin1Char(';'),
180  QStringLiteral("\\;")));
181 
182  address.append((*it).region().replace(QLatin1Char(';'),
183  QStringLiteral("\\;")));
184 
185  address.append((*it).postalCode().replace(QLatin1Char(';'),
186  QStringLiteral("\\;")));
187 
188  address.append((*it).country().replace(QLatin1Char(';'),
189  QStringLiteral("\\;")));
190  // clang-format on
191 
192  const QString addressJoined(address.join(QLatin1Char(';')));
193  VCardLine adrLine(QStringLiteral("ADR"), addressJoined);
194  if (version == VCard::v2_1 && needsEncoding(addressJoined)) {
195  adrLine.addParameter(QStringLiteral("charset"), QStringLiteral("UTF-8"));
196  adrLine.addParameter(QStringLiteral("encoding"), QStringLiteral("QUOTED-PRINTABLE"));
197  }
198 
199  const bool hasLabel = !(*it).label().isEmpty();
200  QStringList addreLineType;
201  QStringList labelLineType;
202  for (unsigned int i = 0; i < s_numAddressTypes; ++i) {
203  if (s_addressTypes[i].flag & (*it).type()) {
204  const QString str = QString::fromLatin1(s_addressTypes[i].addressType);
205  addreLineType << str;
206  if (hasLabel) {
207  labelLineType << str;
208  }
209  }
210  }
211 
212  if (hasLabel) {
213  if (version == VCard::v4_0) {
214  if (!(*it).label().isEmpty()) {
215  adrLine.addParameter(QStringLiteral("LABEL"), QStringLiteral("\"%1\"").arg((*it).label()));
216  }
217  } else {
218  VCardLine labelLine(QStringLiteral("LABEL"), (*it).label());
219  if (version == VCard::v2_1 && needsEncoding((*it).label())) {
220  labelLine.addParameter(QStringLiteral("charset"), QStringLiteral("UTF-8"));
221  labelLine.addParameter(QStringLiteral("encoding"), QStringLiteral("QUOTED-PRINTABLE"));
222  }
223  addParameter(labelLine, version, QStringLiteral("TYPE"), labelLineType);
224  card.addLine(labelLine);
225  }
226  }
227  if (version == VCard::v4_0) {
228  Geo geo = (*it).geo();
229  if (geo.isValid()) {
230  QString str = QString::asprintf("\"geo:%.6f,%.6f\"", geo.latitude(), geo.longitude());
231  adrLine.addParameter(QStringLiteral("GEO"), str);
232  }
233  }
234  if (!isEmpty) {
235  addParameter(adrLine, version, QStringLiteral("TYPE"), addreLineType);
236  card.addLine(adrLine);
237  }
238  }
239 
240  // BDAY
241  const bool withTime = (*addrIt).birthdayHasTime();
242  const QString birthdayString = createDateTime((*addrIt).birthday(), version, withTime);
243  card.addLine(VCardLine(QStringLiteral("BDAY"), birthdayString));
244 
245  // Laurent: 31 Jan 2015. Not necessary to export it. When Categories were changes as AkonadiTag nobody thought that it would break categories support...
246  //=> not necessary to export just tag...
247  // CATEGORIES only > 2.1
248  if (!exportVcard) {
249  if (version != VCard::v2_1) {
250  QStringList categories = (*addrIt).categories();
251  QStringList::Iterator catIt;
252  QStringList::Iterator catEnd(categories.end());
253  for (catIt = categories.begin(); catIt != catEnd; ++catIt) {
254  (*catIt).replace(QLatin1Char(','), QStringLiteral("\\,"));
255  }
256 
257  VCardLine catLine(QStringLiteral("CATEGORIES"), categories.join(QLatin1Char(',')));
258  card.addLine(catLine);
259  }
260  }
261  // MEMBER (only in 4.0)
262  if (version == VCard::v4_0) {
263  // The KIND property must be set to "group" in order to use this property.
264  if ((*addrIt).kind().toLower() == QLatin1String("group")) {
265  const QStringList lst = (*addrIt).members();
266  for (const QString &member : lst) {
267  VCardLine line(QStringLiteral("MEMBER"), member);
268  card.addLine(line);
269  }
270  }
271  }
272  // SOURCE
273  const QVector<QUrl> lstUrl = (*addrIt).sourcesUrlList();
274  for (const QUrl &url : lstUrl) {
275  VCardLine line = VCardLine(QStringLiteral("SOURCE"), url.url());
276  card.addLine(line);
277  }
278 
279  const Related::List relatedList = (*addrIt).relationships();
281  Related::List::ConstIterator relatedEnd(relatedList.end());
282  for (relatedIt = relatedList.begin(); relatedIt != relatedEnd; ++relatedIt) {
283  VCardLine line(QStringLiteral("RELATED"), (*relatedIt).related());
284  addParameters(line, (*relatedIt).parameters());
285  card.addLine(line);
286  }
287  // CLASS only for version == 3.0
288  if (version == VCard::v3_0) {
289  card.addLine(createSecrecy((*addrIt).secrecy()));
290  }
291  // LANG only for version == 4.0
292  if (version == VCard::v4_0) {
293  const Lang::List langList = (*addrIt).langs();
295  Lang::List::ConstIterator langEnd(langList.end());
296  for (langIt = langList.begin(); langIt != langEnd; ++langIt) {
297  VCardLine line(QStringLiteral("LANG"), (*langIt).language());
298  addParameters(line, (*langIt).parameters());
299  card.addLine(line);
300  }
301  }
302  // CLIENTPIDMAP
303  if (version == VCard::v4_0) {
304  const ClientPidMap::List clientpidmapList = (*addrIt).clientPidMapList();
305  ClientPidMap::List::ConstIterator clientPidMapIt;
306  ClientPidMap::List::ConstIterator clientPidMapEnd(clientpidmapList.end());
307  for (clientPidMapIt = clientpidmapList.begin(); clientPidMapIt != clientPidMapEnd; ++clientPidMapIt) {
308  VCardLine line(QStringLiteral("CLIENTPIDMAP"), (*clientPidMapIt).clientPidMap());
309  addParameters(line, (*clientPidMapIt).parameters());
310  card.addLine(line);
311  }
312  }
313  // EMAIL
314  const Email::List emailList = (*addrIt).emailList();
316  Email::List::ConstIterator emailEnd(emailList.end());
317  for (emailIt = emailList.begin(); emailIt != emailEnd; ++emailIt) {
318  VCardLine line(QStringLiteral("EMAIL"), (*emailIt).mail());
319  QMapIterator<QString, QStringList> i((*emailIt).parameters());
320  while (i.hasNext()) {
321  i.next();
322  if (version == VCard::v2_1) {
323  if (i.key().toLower() == QLatin1String("type")) {
324  QStringList valueStringList = i.value();
325  bool hasPreferred = false;
326  const int removeItems = valueStringList.removeAll(QStringLiteral("PREF"));
327  if (removeItems > 0) {
328  hasPreferred = true;
329  }
330  if (!valueStringList.isEmpty()) {
331  addParameter(line, version, i.key(), valueStringList);
332  }
333  if (hasPreferred) {
334  line.addParameter(QStringLiteral("PREF"), QString());
335  }
336  } else {
337  line.addParameter(i.key(), i.value().join(QLatin1Char(',')));
338  }
339  } else {
340  line.addParameter(i.key(), i.value().join(QLatin1Char(',')));
341  }
342  }
343  card.addLine(line);
344  }
345 
346  // FN required for only version > 2.1
347  VCardLine fnLine(QStringLiteral("FN"), (*addrIt).formattedName());
348  if (version == VCard::v2_1 && needsEncoding((*addrIt).formattedName())) {
349  fnLine.addParameter(QStringLiteral("charset"), QStringLiteral("UTF-8"));
350  fnLine.addParameter(QStringLiteral("encoding"), QStringLiteral("QUOTED-PRINTABLE"));
351  }
352  card.addLine(fnLine);
353 
354  // GEO
355  const Geo geo = (*addrIt).geo();
356  if (geo.isValid()) {
357  QString str;
358  if (version == VCard::v4_0) {
359  str = QString::asprintf("geo:%.6f,%.6f", geo.latitude(), geo.longitude());
360  } else {
361  str = QString::asprintf("%.6f;%.6f", geo.latitude(), geo.longitude());
362  }
363  card.addLine(VCardLine(QStringLiteral("GEO"), str));
364  }
365 
366  // KEY
367  const Key::List keys = (*addrIt).keys();
369  Key::List::ConstIterator keyEnd(keys.end());
370  for (keyIt = keys.begin(); keyIt != keyEnd; ++keyIt) {
371  card.addLine(createKey(*keyIt, version));
372  }
373 
374  // LOGO
375  card.addLine(createPicture(QStringLiteral("LOGO"), (*addrIt).logo(), version));
376  const QVector<Picture> lstLogo = (*addrIt).extraLogoList();
377  for (const Picture &logo : lstLogo) {
378  card.addLine(createPicture(QStringLiteral("LOGO"), logo, version));
379  }
380 
381  // MAILER only for version < 4.0
382  if (version != VCard::v4_0) {
383  VCardLine mailerLine(QStringLiteral("MAILER"), (*addrIt).mailer());
384  if (version == VCard::v2_1 && needsEncoding((*addrIt).mailer())) {
385  mailerLine.addParameter(QStringLiteral("charset"), QStringLiteral("UTF-8"));
386  mailerLine.addParameter(QStringLiteral("encoding"), QStringLiteral("QUOTED-PRINTABLE"));
387  }
388  card.addLine(mailerLine);
389  }
390 
391  // clang-format off
392  // N required for only version < 4.0
394  name.append((*addrIt).familyName().replace(QLatin1Char(';'),
395  QStringLiteral("\\;")));
396 
397  name.append((*addrIt).givenName().replace(QLatin1Char(';'),
398  QStringLiteral("\\;")));
399 
400  name.append((*addrIt).additionalName().replace(QLatin1Char(';'),
401  QStringLiteral("\\;")));
402 
403  name.append((*addrIt).prefix().replace(QLatin1Char(';'),
404  QStringLiteral("\\;")));
405 
406  name.append((*addrIt).suffix().replace(QLatin1Char(';'),
407  QStringLiteral("\\;")));
408  // clang-format on
409 
410  VCardLine nLine(QStringLiteral("N"), name.join(QLatin1Char(';')));
411  if (version == VCard::v2_1 && needsEncoding(name.join(QLatin1Char(';')))) {
412  nLine.addParameter(QStringLiteral("charset"), QStringLiteral("UTF-8"));
413  nLine.addParameter(QStringLiteral("encoding"), QStringLiteral("QUOTED-PRINTABLE"));
414  }
415  if (version == VCard::v4_0 && !(*addrIt).sortString().isEmpty()) {
416  nLine.addParameter(QStringLiteral("SORT-AS"), (*addrIt).sortString());
417  }
418 
419  card.addLine(nLine);
420 
421  // NAME only for version < 4.0
422  if (version != VCard::v4_0) {
423  VCardLine nameLine(QStringLiteral("NAME"), (*addrIt).name());
424  if (version == VCard::v2_1 && needsEncoding((*addrIt).name())) {
425  nameLine.addParameter(QStringLiteral("charset"), QStringLiteral("UTF-8"));
426  nameLine.addParameter(QStringLiteral("encoding"), QStringLiteral("QUOTED-PRINTABLE"));
427  }
428  card.addLine(nameLine);
429  }
430 
431  // NICKNAME only for version > 2.1
432  if (version != VCard::v2_1) {
433  const QVector<NickName> lstNickName = (*addrIt).extraNickNameList();
434  for (const NickName &nickName : lstNickName) {
435  VCardLine nickNameLine(QStringLiteral("NICKNAME"), nickName.nickname());
436  addParameters(nickNameLine, nickName.parameters());
437 
438  card.addLine(nickNameLine);
439  }
440  }
441 
442  // NOTE
443  VCardLine noteLine(QStringLiteral("NOTE"), (*addrIt).note());
444  if (version == VCard::v2_1 && needsEncoding((*addrIt).note())) {
445  noteLine.addParameter(QStringLiteral("charset"), QStringLiteral("UTF-8"));
446  noteLine.addParameter(QStringLiteral("encoding"), QStringLiteral("QUOTED-PRINTABLE"));
447  }
448  card.addLine(noteLine);
449 
450  // ORG
451  const QVector<Org> lstOrg = (*addrIt).extraOrganizationList();
452  for (const Org &org : lstOrg) {
453  QStringList organization;
454  organization.append(org.organization().replace(QLatin1Char(';'), QStringLiteral("\\;")));
455  if (!(*addrIt).department().isEmpty()) {
456  organization.append((*addrIt).department().replace(QLatin1Char(';'), QStringLiteral("\\;")));
457  }
458  const QString orgStr = organization.join(QLatin1Char(';'));
459  VCardLine orgLine(QStringLiteral("ORG"), orgStr);
460  if (version == VCard::v2_1 && needsEncoding(orgStr)) {
461  orgLine.addParameter(QStringLiteral("charset"), QStringLiteral("UTF-8"));
462  orgLine.addParameter(QStringLiteral("encoding"), QStringLiteral("QUOTED-PRINTABLE"));
463  }
464  addParameters(orgLine, org.parameters());
465  card.addLine(orgLine);
466  }
467 
468  // PHOTO
469  card.addLine(createPicture(QStringLiteral("PHOTO"), (*addrIt).photo(), version));
470  const QVector<Picture> lstExtraPhoto = (*addrIt).extraPhotoList();
471  for (const Picture &photo : lstExtraPhoto) {
472  card.addLine(createPicture(QStringLiteral("PHOTO"), photo, version));
473  }
474 
475  // PROID only for version > 2.1
476  if (version != VCard::v2_1) {
477  card.addLine(VCardLine(QStringLiteral("PRODID"), (*addrIt).productId()));
478  }
479 
480  // REV
481  card.addLine(VCardLine(QStringLiteral("REV"), createDateTime((*addrIt).revision(), version)));
482 
483  // ROLE
484  const QVector<Role> lstExtraRole = (*addrIt).extraRoleList();
485  for (const Role &role : lstExtraRole) {
486  VCardLine roleLine(QStringLiteral("ROLE"), role.role());
487  if (version == VCard::v2_1 && needsEncoding(role.role())) {
488  roleLine.addParameter(QStringLiteral("charset"), QStringLiteral("UTF-8"));
489  roleLine.addParameter(QStringLiteral("encoding"), QStringLiteral("QUOTED-PRINTABLE"));
490  }
491  addParameters(roleLine, role.parameters());
492  card.addLine(roleLine);
493  }
494 
495  // SORT-STRING
496  if (version == VCard::v3_0) {
497  card.addLine(VCardLine(QStringLiteral("SORT-STRING"), (*addrIt).sortString()));
498  }
499 
500  // SOUND
501  card.addLine(createSound((*addrIt).sound(), version));
502  const QVector<Sound> lstSound = (*addrIt).extraSoundList();
503  for (const Sound &sound : lstSound) {
504  card.addLine(createSound(sound, version));
505  }
506 
507  // TEL
508  const PhoneNumber::List phoneNumbers = (*addrIt).phoneNumbers();
510  PhoneNumber::List::ConstIterator phoneEnd(phoneNumbers.end());
511  for (phoneIt = phoneNumbers.begin(); phoneIt != phoneEnd; ++phoneIt) {
512  VCardLine line(QStringLiteral("TEL"), (*phoneIt).number());
513  QMapIterator<QString, QStringList> i((*phoneIt).parameters());
514  while (i.hasNext()) {
515  i.next();
516  if (i.key().toUpper() != QLatin1String("TYPE")) {
517  line.addParameter(i.key(), i.value().join(QLatin1Char(',')));
518  }
519  }
520 
521  QStringList lst;
522  for (unsigned int i = 0; i < s_numPhoneTypes; ++i) {
523  if (s_phoneTypes[i].flag & (*phoneIt).type()) {
524  const QString str = QString::fromLatin1(s_phoneTypes[i].phoneType);
525  if (version == VCard::v4_0) {
526  lst << str.toLower();
527  } else {
528  lst << str;
529  }
530  }
531  }
532  if (!lst.isEmpty()) {
533  addParameter(line, version, QStringLiteral("TYPE"), lst);
534  }
535  card.addLine(line);
536  }
537 
538  // TITLE
539  const QVector<Title> lstTitle = (*addrIt).extraTitleList();
540  for (const Title &title : lstTitle) {
541  VCardLine titleLine(QStringLiteral("TITLE"), title.title());
542  if (version == VCard::v2_1 && needsEncoding(title.title())) {
543  titleLine.addParameter(QStringLiteral("charset"), QStringLiteral("UTF-8"));
544  titleLine.addParameter(QStringLiteral("encoding"), QStringLiteral("QUOTED-PRINTABLE"));
545  }
546  addParameters(titleLine, title.parameters());
547 
548  card.addLine(titleLine);
549  }
550 
551  // TZ
552  // TODO Add vcard4.0 support
553  const TimeZone timeZone = (*addrIt).timeZone();
554  if (timeZone.isValid()) {
555  int neg = 1;
556  if (timeZone.offset() < 0) {
557  neg = -1;
558  }
559 
560  QString str =
561  QString::asprintf("%c%02d:%02d", (timeZone.offset() >= 0 ? '+' : '-'), (timeZone.offset() / 60) * neg, (timeZone.offset() % 60) * neg);
562 
563  card.addLine(VCardLine(QStringLiteral("TZ"), str));
564  }
565 
566  // UID
567  card.addLine(VCardLine(QStringLiteral("UID"), (*addrIt).uid()));
568 
569  // URL
570  const QVector<ResourceLocatorUrl> lstExtraUrl = (*addrIt).extraUrlList();
571  for (const ResourceLocatorUrl &url : lstExtraUrl) {
572  VCardLine line(QStringLiteral("URL"), url.url());
573  addParameters(line, url.parameters());
574  card.addLine(line);
575  }
576  if (version == VCard::v4_0) {
577  // GENDER
578  const Gender gender = (*addrIt).gender();
579  if (gender.isValid()) {
580  QString genderStr;
581  if (!gender.gender().isEmpty()) {
582  genderStr = gender.gender();
583  }
584  if (!gender.comment().isEmpty()) {
585  genderStr += QLatin1Char(';') + gender.comment();
586  }
587  VCardLine line(QStringLiteral("GENDER"), genderStr);
588  card.addLine(line);
589  }
590  // KIND
591  if (!(*addrIt).kind().isEmpty()) {
592  VCardLine line(QStringLiteral("KIND"), (*addrIt).kind());
593  card.addLine(line);
594  }
595  }
596  // From vcard4.
597  if (version == VCard::v4_0) {
598  const QVector<CalendarUrl> lstCalendarUrl = (*addrIt).calendarUrlList();
599  for (const CalendarUrl &url : lstCalendarUrl) {
600  if (url.isValid()) {
601  QString type;
602  switch (url.type()) {
603  case CalendarUrl::Unknown:
604  case CalendarUrl::EndCalendarType:
605  break;
606  case CalendarUrl::FBUrl:
607  type = QStringLiteral("FBURL");
608  break;
609  case CalendarUrl::CALUri:
610  type = QStringLiteral("CALURI");
611  break;
612  case CalendarUrl::CALADRUri:
613  type = QStringLiteral("CALADRURI");
614  break;
615  }
616  if (!type.isEmpty()) {
617  VCardLine line(type, url.url().toDisplayString());
618  addParameters(line, url.parameters());
619  card.addLine(line);
620  }
621  }
622  }
623  }
624  // FieldGroup
625  const QVector<FieldGroup> lstGroup = (*addrIt).fieldGroupList();
626  for (const FieldGroup &group : lstGroup) {
627  VCardLine line(group.fieldGroupName(), group.value());
628  addParameters(line, group.parameters());
629  card.addLine(line);
630  }
631 
632  // IMPP (supported in vcard 3 too)
633  const QVector<Impp> lstImpp = (*addrIt).imppList();
634  for (const Impp &impp : lstImpp) {
635  VCardLine line(QStringLiteral("IMPP"), impp.address().url());
636  QMapIterator<QString, QStringList> i(impp.parameters());
637  while (i.hasNext()) {
638  i.next();
639  if (i.key().toLower() != QLatin1String("x-service-type")) {
640  line.addParameter(i.key(), i.value().join(QLatin1Char(',')));
641  }
642  }
643  card.addLine(line);
644  }
645 
646  // X-
647  const QStringList customs = (*addrIt).customs();
648  for (strIt = customs.begin(); strIt != customs.end(); ++strIt) {
649  QString identifier = QLatin1String("X-") + (*strIt).left((*strIt).indexOf(QLatin1Char(':')));
650  const QString value = (*strIt).mid((*strIt).indexOf(QLatin1Char(':')) + 1);
651  if (value.isEmpty()) {
652  continue;
653  }
654  // Convert to standard identifier
655  if (exportVcard) {
656  if (identifier == QLatin1String("X-messaging/aim-All")) {
657  identifier = QStringLiteral("X-AIM");
658  } else if (identifier == QLatin1String("X-messaging/icq-All")) {
659  identifier = QStringLiteral("X-ICQ");
660  } else if (identifier == QLatin1String("X-messaging/xmpp-All")) {
661  identifier = QStringLiteral("X-JABBER");
662  } else if (identifier == QLatin1String("X-messaging/msn-All")) {
663  identifier = QStringLiteral("X-MSN");
664  } else if (identifier == QLatin1String("X-messaging/yahoo-All")) {
665  identifier = QStringLiteral("X-YAHOO");
666  } else if (identifier == QLatin1String("X-messaging/gadu-All")) {
667  identifier = QStringLiteral("X-GADUGADU");
668  } else if (identifier == QLatin1String("X-messaging/skype-All")) {
669  identifier = QStringLiteral("X-SKYPE");
670  } else if (identifier == QLatin1String("X-messaging/groupwise-All")) {
671  identifier = QStringLiteral("X-GROUPWISE");
672  } else if (identifier == QLatin1String("X-messaging/sms-All")) {
673  identifier = QStringLiteral("X-SMS");
674  } else if (identifier == QLatin1String("X-messaging/meanwhile-All")) {
675  identifier = QStringLiteral("X-MEANWHILE");
676  } else if (identifier == QLatin1String("X-messaging/irc-All")) {
677  identifier = QStringLiteral("X-IRC"); // Not defined by rfc but need for fixing #300869
678  } else if (identifier == QLatin1String("X-messaging/googletalk-All")) {
679  // Not defined by rfc but need for fixing #300869
680  identifier = QStringLiteral("X-GTALK");
681  } else if (identifier == QLatin1String("X-messaging/twitter-All")) {
682  identifier = QStringLiteral("X-TWITTER");
683  }
684  }
685  if (identifier.toLower() == QLatin1String("x-kaddressbook-x-anniversary") && version == VCard::v4_0) {
686  // ANNIVERSARY
687  if (!value.isEmpty()) {
688  const QDate date = QDate::fromString(value, Qt::ISODate);
689  QDateTime dt = QDateTime(date.startOfDay());
690  dt.setTime(QTime());
691  VCardLine line(QStringLiteral("ANNIVERSARY"), createDateTime(dt, version, false));
692  card.addLine(line);
693  }
694  } else if (identifier.toLower() == QLatin1String("x-kaddressbook-x-spousesname") && version == VCard::v4_0) {
695  if (!value.isEmpty()) {
696  VCardLine line(QStringLiteral("RELATED"), QStringLiteral(";"));
697  line.addParameter(QStringLiteral("TYPE"), QStringLiteral("spouse"));
698  line.addParameter(QStringLiteral("VALUE"), value);
699  card.addLine(line);
700  }
701  } else {
702  VCardLine line(identifier, value);
703  if (version == VCard::v2_1 && needsEncoding(value)) {
704  line.addParameter(QStringLiteral("charset"), QStringLiteral("UTF-8"));
705  line.addParameter(QStringLiteral("encoding"), QStringLiteral("QUOTED-PRINTABLE"));
706  }
707  card.addLine(line);
708  }
709  }
710 
711  vCardList.append(card);
712  }
713 
714  return VCardParser::createVCards(vCardList);
715 }
716 
717 Addressee::List VCardTool::parseVCards(const QByteArray &vcard) const
718 {
719  static const QLatin1Char semicolonSep(';');
720  static const QLatin1Char commaSep(',');
721  QString identifier;
722  QString group;
723  Addressee::List addrList;
724  const VCard::List vCardList = VCardParser::parseVCards(vcard);
725 
727  VCard::List::ConstIterator listEnd(vCardList.end());
728  for (cardIt = vCardList.begin(); cardIt != listEnd; ++cardIt) {
729  Addressee addr;
730 
731  const QStringList idents = (*cardIt).identifiers();
733  QStringList::ConstIterator identEnd(idents.end());
734  for (identIt = idents.begin(); identIt != identEnd; ++identIt) {
735  const VCardLine::List lines = (*cardIt).lines((*identIt));
737 
738  // iterate over the lines
739  for (lineIt = lines.begin(); lineIt != lines.end(); ++lineIt) {
740  identifier = (*lineIt).identifier().toLower();
741  group = (*lineIt).group();
742  if (!group.isEmpty() && identifier != QLatin1String("adr")) {
743  KContacts::FieldGroup groupField(group + QLatin1Char('.') + (*lineIt).identifier());
744  groupField.setParameters((*lineIt).parameterMap());
745  groupField.setValue((*lineIt).value().toString());
746  addr.insertFieldGroup(groupField);
747  }
748  // ADR
749  else if (identifier == QLatin1String("adr")) {
750  Address address;
751  const QStringList addrParts = splitString(semicolonSep, (*lineIt).value().toString());
752  const int addrPartsCount(addrParts.count());
753  if (addrPartsCount > 0) {
754  address.setPostOfficeBox(addrParts.at(0));
755  }
756  if (addrPartsCount > 1) {
757  address.setExtended(addrParts.at(1));
758  }
759  if (addrPartsCount > 2) {
760  address.setStreet(addrParts.at(2));
761  }
762  if (addrPartsCount > 3) {
763  address.setLocality(addrParts.at(3));
764  }
765  if (addrPartsCount > 4) {
766  address.setRegion(addrParts.at(4));
767  }
768  if (addrPartsCount > 5) {
769  address.setPostalCode(addrParts.at(5));
770  }
771  if (addrPartsCount > 6) {
772  address.setCountry(addrParts.at(6));
773  }
774 
775  Address::Type type;
776 
777  const QStringList types = (*lineIt).parameters(QStringLiteral("type"));
779  for (QStringList::ConstIterator it = types.begin(); it != end; ++it) {
780  type |= stringToAddressType((*it).toLower());
781  }
782 
783  address.setType(type);
784  QString label = (*lineIt).parameter(QStringLiteral("label"));
785  if (!label.isEmpty()) {
786  if (label.length() > 1) {
787  if (label.at(0) == QLatin1Char('"') && label.at(label.length() - 1) == QLatin1Char('"')) {
788  label = label.mid(1, label.length() - 2);
789  }
790  }
791  address.setLabel(label);
792  }
793  QString geoStr = (*lineIt).parameter(QStringLiteral("geo"));
794  if (!geoStr.isEmpty()) {
795  geoStr.remove(QLatin1Char('\"'));
796  geoStr.remove(QStringLiteral("geo:"));
797  if (geoStr.contains(QLatin1Char(','))) {
798  QStringList arguments = geoStr.split(QLatin1Char(','));
799  KContacts::Geo geo;
800  geo.setLatitude(arguments.at(0).toDouble());
801  geo.setLongitude(arguments.at(1).toDouble());
802  address.setGeo(geo);
803  }
804  }
805  addr.insertAddress(address);
806  }
807  // ANNIVERSARY
808  else if (identifier == QLatin1String("anniversary")) {
809  const QString t = (*lineIt).value().toString();
810  const QDateTime dt(parseDateTime(t));
811  addr.insertCustom(QStringLiteral("KADDRESSBOOK"), QStringLiteral("X-Anniversary"), dt.date().toString(Qt::ISODate));
812  }
813  // BDAY
814  else if (identifier == QLatin1String("bday")) {
815  bool withTime;
816  const QDateTime bday = parseDateTime((*lineIt).value().toString(), &withTime);
817  addr.setBirthday(bday, withTime);
818  }
819  // CATEGORIES
820  else if (identifier == QLatin1String("categories")) {
821  const QStringList categories = splitString(commaSep, (*lineIt).value().toString());
822  addr.setCategories(categories);
823  }
824  // FBURL
825  else if (identifier == QLatin1String("fburl")) {
826  CalendarUrl calurl;
827  calurl.setType(CalendarUrl::FBUrl);
828  const QUrl url = QUrl((*lineIt).value().toString());
829  calurl.setUrl(url);
830  calurl.setParameters((*lineIt).parameterMap());
831  addr.insertCalendarUrl(calurl);
832  }
833  // CALADRURI
834  else if (identifier == QLatin1String("caladruri")) {
835  CalendarUrl calurl;
836  calurl.setType(CalendarUrl::CALADRUri);
837  const QUrl url = QUrl((*lineIt).value().toString());
838  calurl.setUrl(url);
839  calurl.setParameters((*lineIt).parameterMap());
840  addr.insertCalendarUrl(calurl);
841  }
842  // CALURI
843  else if (identifier == QLatin1String("caluri")) {
844  CalendarUrl calurl;
845  calurl.setType(CalendarUrl::CALUri);
846  const QUrl url = QUrl((*lineIt).value().toString());
847  calurl.setUrl(url);
848  calurl.setParameters((*lineIt).parameterMap());
849  addr.insertCalendarUrl(calurl);
850  }
851  // IMPP
852  else if (identifier == QLatin1String("impp")) {
853  QUrl imppUrl((*lineIt).value().toString());
854  Impp impp;
855  impp.setParameters((*lineIt).parameterMap());
856  if (!(*lineIt).parameter(QStringLiteral("x-service-type")).isEmpty() && imppUrl.scheme().isEmpty()) {
857  imppUrl.setScheme(normalizeImppServiceType((*lineIt).parameter(QStringLiteral("x-service-type")).toLower()));
858  }
859  impp.setAddress(imppUrl);
860  addr.insertImpp(impp);
861  }
862  // CLASS
863  else if (identifier == QLatin1String("class")) {
864  addr.setSecrecy(parseSecrecy(*lineIt));
865  }
866  // GENDER
867  else if (identifier == QLatin1String("gender")) {
868  QString genderStr = (*lineIt).value().toString();
869  if (!genderStr.isEmpty()) {
870  Gender gender;
871  if (genderStr.at(0) != QLatin1Char(';')) {
872  gender.setGender(genderStr.at(0));
873  if (genderStr.length() > 2 && (genderStr.at(1) == QLatin1Char(';'))) {
874  gender.setComment(genderStr.right(genderStr.length() - 2));
875  }
876  } else {
877  gender.setComment(genderStr.right(genderStr.length() - 1));
878  }
879  addr.setGender(gender);
880  }
881  }
882  // LANG
883  else if (identifier == QLatin1String("lang")) {
884  Lang lang;
885  lang.setLanguage((*lineIt).value().toString());
886  lang.setParameters((*lineIt).parameterMap());
887  addr.insertLang(lang);
888  }
889  // EMAIL
890  else if (identifier == QLatin1String("email")) {
891  const QStringList types = (*lineIt).parameters(QStringLiteral("type"));
892  addr.insertEmail((*lineIt).value().toString(), types.contains(QLatin1String("PREF")), (*lineIt).parameterMap());
893  }
894  // KIND
895  else if (identifier == QLatin1String("kind")) {
896  addr.setKind((*lineIt).value().toString());
897  }
898  // FN
899  else if (identifier == QLatin1String("fn")) {
900  addr.setFormattedName((*lineIt).value().toString());
901  }
902  // GEO
903  else if (identifier == QLatin1String("geo")) {
904  Geo geo;
905  QString lineStr = (*lineIt).value().toString();
906  if (lineStr.startsWith(QLatin1String("geo:"))) { // VCard 4.0
907  lineStr.remove(QStringLiteral("geo:"));
908  const QStringList geoParts = lineStr.split(QLatin1Char(','), Qt::KeepEmptyParts);
909  if (geoParts.size() >= 2) {
910  geo.setLatitude(geoParts.at(0).toFloat());
911  geo.setLongitude(geoParts.at(1).toFloat());
912  addr.setGeo(geo);
913  }
914  } else {
915  const QStringList geoParts = lineStr.split(QLatin1Char(';'), Qt::KeepEmptyParts);
916  if (geoParts.size() >= 2) {
917  geo.setLatitude(geoParts.at(0).toFloat());
918  geo.setLongitude(geoParts.at(1).toFloat());
919  addr.setGeo(geo);
920  }
921  }
922  }
923  // KEY
924  else if (identifier == QLatin1String("key")) {
925  addr.insertKey(parseKey(*lineIt));
926  }
927  // LABEL
928  else if (identifier == QLatin1String("label")) {
929  Address::Type type;
930 
931  const QStringList types = (*lineIt).parameters(QStringLiteral("type"));
933  for (QStringList::ConstIterator it = types.begin(); it != end; ++it) {
934  type |= stringToAddressType((*it).toLower());
935  }
936 
937  bool available = false;
938  KContacts::Address::List addressList = addr.addresses();
939  for (KContacts::Address::List::Iterator it = addressList.begin(); it != addressList.end(); ++it) {
940  if ((*it).type() == type) {
941  (*it).setLabel((*lineIt).value().toString());
942  addr.insertAddress(*it);
943  available = true;
944  break;
945  }
946  }
947 
948  if (!available) { // a standalone LABEL tag
949  KContacts::Address address(type);
950  address.setLabel((*lineIt).value().toString());
951  addr.insertAddress(address);
952  }
953  }
954  // LOGO
955  else if (identifier == QLatin1String("logo")) {
956  Picture picture = parsePicture(*lineIt);
957  if (addr.logo().isEmpty()) {
958  addr.setLogo(picture);
959  } else {
960  addr.insertExtraLogo(picture);
961  }
962  }
963  // MAILER
964  else if (identifier == QLatin1String("mailer")) {
965  addr.setMailer((*lineIt).value().toString());
966  }
967  // N
968  else if (identifier == QLatin1Char('n')) {
969  const QStringList nameParts = splitString(semicolonSep, (*lineIt).value().toString());
970  const int numberOfParts(nameParts.count());
971  if (numberOfParts > 0) {
972  addr.setFamilyName(nameParts.at(0));
973  }
974  if (numberOfParts > 1) {
975  addr.setGivenName(nameParts.at(1));
976  }
977  if (numberOfParts > 2) {
978  addr.setAdditionalName(nameParts.at(2));
979  }
980  if (numberOfParts > 3) {
981  addr.setPrefix(nameParts.at(3));
982  }
983  if (numberOfParts > 4) {
984  addr.setSuffix(nameParts.at(4));
985  }
986  if (!(*lineIt).parameter(QStringLiteral("sort-as")).isEmpty()) {
987  addr.setSortString((*lineIt).parameter(QStringLiteral("sort-as")));
988  }
989  }
990  // NAME
991  else if (identifier == QLatin1String("name")) {
992  addr.setName((*lineIt).value().toString());
993  }
994  // NICKNAME
995  else if (identifier == QLatin1String("nickname")) {
996  NickName nickName((*lineIt).value().toString());
997  nickName.setParameters((*lineIt).parameterMap());
998  addr.insertExtraNickName(nickName);
999  }
1000  // NOTE
1001  else if (identifier == QLatin1String("note")) {
1002  addr.setNote((*lineIt).value().toString());
1003  }
1004  // ORGANIZATION
1005  else if (identifier == QLatin1String("org")) {
1006  const QStringList orgParts = splitString(semicolonSep, (*lineIt).value().toString());
1007  const int orgPartsCount(orgParts.count());
1008  if (orgPartsCount > 0) {
1009  Org organization(orgParts.at(0));
1010  organization.setParameters((*lineIt).parameterMap());
1011  addr.insertExtraOrganization(organization);
1012  }
1013  if (orgPartsCount > 1) {
1014  addr.setDepartment(orgParts.at(1));
1015  }
1016  if (!(*lineIt).parameter(QStringLiteral("sort-as")).isEmpty()) {
1017  addr.setSortString((*lineIt).parameter(QStringLiteral("sort-as")));
1018  }
1019  }
1020  // PHOTO
1021  else if (identifier == QLatin1String("photo")) {
1022  Picture picture = parsePicture(*lineIt);
1023  if (addr.photo().isEmpty()) {
1024  addr.setPhoto(picture);
1025  } else {
1026  addr.insertExtraPhoto(picture);
1027  }
1028  }
1029  // PROID
1030  else if (identifier == QLatin1String("prodid")) {
1031  addr.setProductId((*lineIt).value().toString());
1032  }
1033  // REV
1034  else if (identifier == QLatin1String("rev")) {
1035  addr.setRevision(parseDateTime((*lineIt).value().toString()));
1036  }
1037  // ROLE
1038  else if (identifier == QLatin1String("role")) {
1039  Role role((*lineIt).value().toString());
1040  role.setParameters((*lineIt).parameterMap());
1041  addr.insertExtraRole(role);
1042  }
1043  // SORT-STRING
1044  else if (identifier == QLatin1String("sort-string")) {
1045  addr.setSortString((*lineIt).value().toString());
1046  }
1047  // SOUND
1048  else if (identifier == QLatin1String("sound")) {
1049  Sound sound = parseSound(*lineIt);
1050  if (addr.sound().isEmpty()) {
1051  addr.setSound(sound);
1052  } else {
1053  addr.insertExtraSound(sound);
1054  }
1055  }
1056  // TEL
1057  else if (identifier == QLatin1String("tel")) {
1058  PhoneNumber phone;
1059  phone.setNumber((*lineIt).value().toString());
1060 
1061  PhoneNumber::Type type;
1062  bool foundType = false;
1063  const QStringList types = (*lineIt).parameters(QStringLiteral("type"));
1064  QStringList::ConstIterator typeEnd(types.constEnd());
1065  for (QStringList::ConstIterator it = types.constBegin(); it != typeEnd; ++it) {
1066  type |= stringToPhoneType((*it).toUpper());
1067  foundType = true;
1068  }
1069  phone.setType(foundType ? type : PhoneNumber::Undefined);
1070  phone.setParameters((*lineIt).parameterMap());
1071 
1072  addr.insertPhoneNumber(phone);
1073  }
1074  // TITLE
1075  else if (identifier == QLatin1String("title")) {
1076  Title title((*lineIt).value().toString());
1077  title.setParameters((*lineIt).parameterMap());
1078  addr.insertExtraTitle(title);
1079  }
1080  // TZ
1081  else if (identifier == QLatin1String("tz")) {
1082  // TODO add vcard4 support
1083  TimeZone tz;
1084  const QString date = (*lineIt).value().toString();
1085 
1086  if (!date.isEmpty()) {
1087 #if QT_VERSION >= QT_VERSION_CHECK(6, 0, 0)
1088  const QStringView dateView(date);
1089  int hours = dateView.mid(1, 2).toInt();
1090  int minutes = dateView.mid(4, 2).toInt();
1091 #else
1092  int hours = date.midRef(1, 2).toInt();
1093  int minutes = date.midRef(4, 2).toInt();
1094 #endif
1095  int offset = (hours * 60) + minutes;
1096  offset = offset * (date[0] == QLatin1Char('+') ? 1 : -1);
1097 
1098  tz.setOffset(offset);
1099  addr.setTimeZone(tz);
1100  }
1101  }
1102  // UID
1103  else if (identifier == QLatin1String("uid")) {
1104  addr.setUid((*lineIt).value().toString());
1105  }
1106  // URL
1107  else if (identifier == QLatin1String("url")) {
1108  const QUrl url = QUrl((*lineIt).value().toString());
1109  ResourceLocatorUrl resourceLocatorUrl;
1110  resourceLocatorUrl.setUrl(url);
1111  resourceLocatorUrl.setParameters((*lineIt).parameterMap());
1112  addr.insertExtraUrl(resourceLocatorUrl);
1113  }
1114  // SOURCE
1115  else if (identifier == QLatin1String("source")) {
1116  const QUrl url = QUrl((*lineIt).value().toString());
1117  addr.insertSourceUrl(url);
1118  }
1119  // MEMBER (vcard 4.0)
1120  else if (identifier == QLatin1String("member")) {
1121  addr.insertMember((*lineIt).value().toString());
1122  }
1123  // RELATED (vcard 4.0)
1124  else if (identifier == QLatin1String("related")) {
1125  Related related;
1126  related.setRelated((*lineIt).value().toString());
1127  related.setParameters((*lineIt).parameterMap());
1128  addr.insertRelationship(related);
1129  }
1130  // CLIENTPIDMAP (vcard 4.0)
1131  else if (identifier == QLatin1String("clientpidmap")) {
1132  ClientPidMap clientpidmap;
1133  clientpidmap.setClientPidMap((*lineIt).value().toString());
1134  clientpidmap.setParameters((*lineIt).parameterMap());
1135  addr.insertClientPidMap(clientpidmap);
1136  }
1137  // X-
1138  // TODO import X-GENDER
1139  else if (identifier.startsWith(QLatin1String("x-"))) {
1140  QString ident = (*lineIt).identifier();
1141  // clang-format off
1142  //X-Evolution
1143  // also normalize case of our own extensions, some backends "adjust" that
1144  if (identifier == QLatin1String("x-evolution-spouse")
1145  || identifier == QLatin1String("x-spouse")) {
1146  ident = QStringLiteral("X-KADDRESSBOOK-X-SpousesName");
1147  } else if (identifier == QLatin1String("x-evolution-blog-url") || identifier.compare(QLatin1String("X-KADDRESSBOOK-BLOGFEED"), Qt::CaseInsensitive) == 0) {
1148  ident = QStringLiteral("X-KADDRESSBOOK-BlogFeed");
1149  } else if (identifier == QLatin1String("x-evolution-assistant")
1150  || identifier == QLatin1String("x-assistant")
1151  || identifier.compare(QLatin1String("X-KADDRESSBOOK-X-ASSISTANTSNAME"), Qt::CaseInsensitive) == 0) {
1152  ident = QStringLiteral("X-KADDRESSBOOK-X-AssistantsName");
1153  } else if (identifier == QLatin1String("x-evolution-anniversary")
1154  || identifier == QLatin1String("x-anniversary")
1155  || identifier.compare(QLatin1String("X-KADDRESSBOOK-X-ANNIVERSARY"), Qt::CaseInsensitive) == 0) {
1156  ident = QStringLiteral("X-KADDRESSBOOK-X-Anniversary");
1157  } else if (identifier == QLatin1String("x-evolution-manager")
1158  || identifier == QLatin1String("x-manager")
1159  || identifier.compare(QLatin1String("X-KADDRESSBOOK-X-MANAGERSNAME"), Qt::CaseInsensitive) == 0) {
1160  // clang-format on
1161  ident = QStringLiteral("X-KADDRESSBOOK-X-ManagersName");
1162  } else if (identifier.compare(QLatin1String("X-KADDRESSBOOK-X-PROFESSION"), Qt::CaseInsensitive) == 0) {
1163  ident = QStringLiteral("X-KADDRESSBOOK-X-Profession");
1164  } else if (identifier.compare(QLatin1String("X-KADDRESSBOOK-X-OFFICE"), Qt::CaseInsensitive) == 0) {
1165  ident = QStringLiteral("X-KADDRESSBOOK-X-Office");
1166  } else if (identifier.compare(QLatin1String("X-KADDRESSBOOK-X-SPOUSESNAME"), Qt::CaseInsensitive) == 0) {
1167  ident = QStringLiteral("X-KADDRESSBOOK-X-SpousesName");
1168  } else if (identifier == QLatin1String("x-aim")) {
1169  ident = QStringLiteral("X-messaging/aim-All");
1170  } else if (identifier == QLatin1String("x-icq")) {
1171  ident = QStringLiteral("X-messaging/icq-All");
1172  } else if (identifier == QLatin1String("x-jabber")) {
1173  ident = QStringLiteral("X-messaging/xmpp-All");
1174  } else if (identifier == QLatin1String("x-jabber")) {
1175  ident = QStringLiteral("X-messaging/xmpp-All");
1176  } else if (identifier == QLatin1String("x-msn")) {
1177  ident = QStringLiteral("X-messaging/msn-All");
1178  } else if (identifier == QLatin1String("x-yahoo")) {
1179  ident = QStringLiteral("X-messaging/yahoo-All");
1180  } else if (identifier == QLatin1String("x-gadugadu")) {
1181  ident = QStringLiteral("X-messaging/gadu-All");
1182  } else if (identifier == QLatin1String("x-skype")) {
1183  ident = QStringLiteral("X-messaging/skype-All");
1184  } else if (identifier == QLatin1String("x-groupwise")) {
1185  ident = QStringLiteral("X-messaging/groupwise-All");
1186  } else if (identifier == QLatin1String("x-sms")) {
1187  ident = QStringLiteral("X-messaging/sms-All");
1188  } else if (identifier == QLatin1String("x-meanwhile")) {
1189  ident = QStringLiteral("X-messaging/meanwhile-All");
1190  } else if (identifier == QLatin1String("x-irc")) {
1191  ident = QStringLiteral("X-messaging/irc-All");
1192  } else if (identifier == QLatin1String("x-gtalk")) {
1193  ident = QStringLiteral("X-messaging/googletalk-All");
1194  } else if (identifier == QLatin1String("x-twitter")) {
1195  ident = QStringLiteral("X-messaging/twitter-All");
1196  }
1197 
1198  const QString key = ident.mid(2);
1199  const int dash = key.indexOf(QLatin1Char('-'));
1200 
1201  // convert legacy messaging fields into IMPP ones
1202  if (key.startsWith(QLatin1String("messaging/"))) {
1203  QUrl url;
1204  url.setScheme(normalizeImppServiceType(key.mid(10, dash - 10)));
1205  const auto values = (*lineIt).value().toString().split(QChar(0xE000), Qt::SkipEmptyParts);
1206  for (const auto &value : values) {
1207  url.setPath(value);
1208  Impp impp;
1209  impp.setParameters((*lineIt).parameterMap());
1210  impp.setAddress(url);
1211  addr.insertImpp(impp);
1212  }
1213  } else {
1214  addr.insertCustom(key.left(dash), key.mid(dash + 1), (*lineIt).value().toString());
1215  }
1216  }
1217  }
1218  }
1219 
1220  addrList.append(addr);
1221  }
1222 
1223  return addrList;
1224 }
1225 
1226 QDateTime VCardTool::parseDateTime(const QString &str, bool *timeValid)
1227 {
1228  const int posT = str.indexOf(QLatin1Char('T'));
1229  QString dateString = posT >= 0 ? str.left(posT) : str;
1230  const bool noYear = dateString.startsWith(QLatin1String("--"));
1231  dateString.remove(QLatin1Char('-'));
1232  QDate date;
1233  if (noYear) {
1234  date = QDate::fromString(dateString, QStringLiteral("MMdd"));
1235  date = date.addYears(-1900);
1236  } else {
1237  date = QDate::fromString(dateString, QStringLiteral("yyyyMMdd"));
1238  }
1239 
1240  QTime time;
1241  Qt::TimeSpec spec = Qt::LocalTime;
1242  int offsetSecs = 0;
1243  if (posT >= 0) {
1244  QString timeString = str.mid(posT + 1);
1245  timeString.remove(QLatin1Char(':'));
1246  const int zPos = timeString.indexOf(QLatin1Char('Z'));
1247  const int plusPos = timeString.indexOf(QLatin1Char('+'));
1248  const int minusPos = timeString.indexOf(QLatin1Char('-'));
1249  const int tzPos = qMax(qMax(zPos, plusPos), minusPos);
1250  const QString hhmmssString = tzPos >= 0 ? timeString.left(tzPos) : timeString;
1251  switch (hhmmssString.size()) {
1252  case 2:
1253  time = QTime::fromString(hhmmssString, QStringLiteral("hh"));
1254  break;
1255  case 4:
1256  time = QTime::fromString(hhmmssString, QStringLiteral("hhmm"));
1257  break;
1258  case 6:
1259  time = QTime::fromString(hhmmssString, QStringLiteral("hhmmss"));
1260  break;
1261  }
1262  if (tzPos >= 0) {
1263  if (zPos >= 0) {
1264  spec = Qt::UTC;
1265  } else {
1266  spec = Qt::OffsetFromUTC;
1267  QTime offsetTime;
1268  const QString offsetString = timeString.mid(tzPos + 1);
1269  switch (offsetString.size()) {
1270  case 2:
1271  offsetTime = QTime::fromString(offsetString, QStringLiteral("hh"));
1272  break;
1273  case 4:
1274  offsetTime = QTime::fromString(offsetString, QStringLiteral("hhmm"));
1275  break;
1276  }
1277  offsetSecs = offsetTime.hour() * 3600 + offsetTime.minute() * 60;
1278  }
1279  if (minusPos >= 0) {
1280  offsetSecs *= -1;
1281  }
1282  }
1283  }
1284  if (timeValid) {
1285  *timeValid = time.isValid();
1286  }
1287 
1288  return QDateTime(date, time, spec, offsetSecs);
1289 }
1290 
1291 QString VCardTool::createDateTime(const QDateTime &dateTime, VCard::Version version, bool withTime)
1292 {
1293  if (!dateTime.date().isValid()) {
1294  return QString();
1295  }
1296  QString str = createDate(dateTime.date(), version);
1297  if (!withTime) {
1298  return str;
1299  }
1300  str += createTime(dateTime.time(), version);
1301  if (dateTime.timeSpec() == Qt::UTC) {
1302  str += QLatin1Char('Z');
1303  } else if (dateTime.timeSpec() == Qt::OffsetFromUTC) {
1304  const int offsetSecs = dateTime.offsetFromUtc();
1305  if (offsetSecs >= 0) {
1306  str += QLatin1Char('+');
1307  } else {
1308  str += QLatin1Char('-');
1309  }
1310  QTime offsetTime = QTime(0, 0).addSecs(abs(offsetSecs));
1311  if (version == VCard::v4_0) {
1312  str += offsetTime.toString(QStringLiteral("HHmm"));
1313  } else {
1314  str += offsetTime.toString(QStringLiteral("HH:mm"));
1315  }
1316  }
1317  return str;
1318 }
1319 
1320 QString VCardTool::createDate(const QDate &date, VCard::Version version)
1321 {
1322  QString format;
1323  if (date.year() > 0) {
1324  format = QStringLiteral("yyyyMMdd");
1325  } else {
1326  format = QStringLiteral("--MMdd");
1327  }
1328  if (version != VCard::v4_0) {
1329  format.replace(QStringLiteral("yyyy"), QStringLiteral("yyyy-"));
1330  format.replace(QStringLiteral("MM"), QStringLiteral("MM-"));
1331  }
1332  return date.toString(format);
1333 }
1334 
1335 QString VCardTool::createTime(const QTime &time, VCard::Version version)
1336 {
1337  QString format;
1338  if (version == VCard::v4_0) {
1339  format = QStringLiteral("HHmmss");
1340  } else {
1341  format = QStringLiteral("HH:mm:ss");
1342  }
1343  return QLatin1Char('T') + time.toString(format);
1344 }
1345 
1346 Picture VCardTool::parsePicture(const VCardLine &line) const
1347 {
1348  Picture pic;
1349 
1350  const QStringList params = line.parameterList();
1351  QString type;
1352  if (params.contains(QLatin1String("type"))) {
1353  type = line.parameter(QStringLiteral("type"));
1354  }
1355  if (params.contains(QLatin1String("encoding"))) {
1356  pic.setRawData(line.value().toByteArray(), type);
1357  } else if (params.contains(QLatin1String("value"))) {
1358  if (line.parameter(QStringLiteral("value")).toLower() == QLatin1String("uri")) {
1359  pic.setUrl(line.value().toString());
1360  }
1361  }
1362 
1363  return pic;
1364 }
1365 
1366 VCardLine VCardTool::createPicture(const QString &identifier, const Picture &pic, VCard::Version version) const
1367 {
1368  VCardLine line(identifier);
1369 
1370  if (pic.isEmpty()) {
1371  return line;
1372  }
1373 
1374  if (pic.isIntern()) {
1375  line.setValue(pic.rawData());
1376  if (version == VCard::v2_1) {
1377  line.addParameter(QStringLiteral("ENCODING"), QStringLiteral("BASE64"));
1378  line.addParameter(pic.type(), QString());
1379  } else { /*if (version == VCard::v3_0) */
1380  line.addParameter(QStringLiteral("encoding"), QStringLiteral("b"));
1381  line.addParameter(QStringLiteral("type"), pic.type());
1382 #if 0
1383  } else { //version 4.0
1384  line.addParameter(QStringLiteral("data") + QStringLiteral(":image/") + pic.type(), QStringLiteral("base64"));
1385 #endif
1386  }
1387  } else {
1388  line.setValue(pic.url());
1389  line.addParameter(QStringLiteral("value"), QStringLiteral("URI"));
1390  }
1391 
1392  return line;
1393 }
1394 
1395 Sound VCardTool::parseSound(const VCardLine &line) const
1396 {
1397  Sound snd;
1398 
1399  const QStringList params = line.parameterList();
1400  if (params.contains(QLatin1String("encoding"))) {
1401  snd.setData(line.value().toByteArray());
1402  } else if (params.contains(QLatin1String("value"))) {
1403  if (line.parameter(QStringLiteral("value")).toLower() == QLatin1String("uri")) {
1404  snd.setUrl(line.value().toString());
1405  }
1406  }
1407 
1408  /* TODO: support sound types
1409  if ( params.contains( "type" ) )
1410  snd.setType( line.parameter( "type" ) );
1411  */
1412 
1413  return snd;
1414 }
1415 
1416 VCardLine VCardTool::createSound(const Sound &snd, VCard::Version version) const
1417 {
1418  Q_UNUSED(version);
1419  VCardLine line(QStringLiteral("SOUND"));
1420 
1421  if (snd.isIntern()) {
1422  if (!snd.data().isEmpty()) {
1423  line.setValue(snd.data());
1424  if (version == VCard::v2_1) {
1425  line.addParameter(QStringLiteral("ENCODING"), QStringLiteral("BASE64"));
1426  } else {
1427  line.addParameter(QStringLiteral("encoding"), QStringLiteral("b"));
1428  }
1429  // TODO: need to store sound type!!!
1430  }
1431  } else if (!snd.url().isEmpty()) {
1432  line.setValue(snd.url());
1433  line.addParameter(QStringLiteral("value"), QStringLiteral("URI"));
1434  }
1435 
1436  return line;
1437 }
1438 
1439 Key VCardTool::parseKey(const VCardLine &line) const
1440 {
1441  Key key;
1442 
1443  const QStringList params = line.parameterList();
1444  if (params.contains(QLatin1String("encoding"))) {
1445  key.setBinaryData(line.value().toByteArray());
1446  } else {
1447  key.setTextData(line.value().toString());
1448  }
1449 
1450  if (params.contains(QLatin1String("type"))) {
1451  if (line.parameter(QStringLiteral("type")).toLower() == QLatin1String("x509")) {
1452  key.setType(Key::X509);
1453  } else if (line.parameter(QStringLiteral("type")).toLower() == QLatin1String("pgp")) {
1454  key.setType(Key::PGP);
1455  } else {
1456  key.setType(Key::Custom);
1457  key.setCustomTypeString(line.parameter(QStringLiteral("type")));
1458  }
1459  } else if (params.contains(QLatin1String("mediatype"))) {
1460  const QString param = line.parameter(QStringLiteral("mediatype")).toLower();
1461  if (param == QLatin1String("application/x-x509-ca-cert")) {
1462  key.setType(Key::X509);
1463  } else if (param == QLatin1String("application/pgp-keys")) {
1464  key.setType(Key::PGP);
1465  } else {
1466  key.setType(Key::Custom);
1467  key.setCustomTypeString(line.parameter(QStringLiteral("type")));
1468  }
1469  }
1470 
1471  return key;
1472 }
1473 
1474 VCardLine VCardTool::createKey(const Key &key, VCard::Version version) const
1475 {
1476  VCardLine line(QStringLiteral("KEY"));
1477 
1478  if (key.isBinary()) {
1479  if (!key.binaryData().isEmpty()) {
1480  line.setValue(key.binaryData());
1481  if (version == VCard::v2_1) {
1482  line.addParameter(QStringLiteral("ENCODING"), QStringLiteral("BASE64"));
1483  } else {
1484  line.addParameter(QStringLiteral("encoding"), QStringLiteral("b"));
1485  }
1486  }
1487  } else if (!key.textData().isEmpty()) {
1488  line.setValue(key.textData());
1489  }
1490 
1491  if (version == VCard::v4_0) {
1492  if (key.type() == Key::X509) {
1493  line.addParameter(QStringLiteral("MEDIATYPE"), QStringLiteral("application/x-x509-ca-cert"));
1494  } else if (key.type() == Key::PGP) {
1495  line.addParameter(QStringLiteral("MEDIATYPE"), QStringLiteral("application/pgp-keys"));
1496  } else if (key.type() == Key::Custom) {
1497  line.addParameter(QStringLiteral("MEDIATYPE"), key.customTypeString());
1498  }
1499  } else {
1500  if (key.type() == Key::X509) {
1501  line.addParameter(QStringLiteral("type"), QStringLiteral("X509"));
1502  } else if (key.type() == Key::PGP) {
1503  line.addParameter(QStringLiteral("type"), QStringLiteral("PGP"));
1504  } else if (key.type() == Key::Custom) {
1505  line.addParameter(QStringLiteral("type"), key.customTypeString());
1506  }
1507  }
1508 
1509  return line;
1510 }
1511 
1512 Secrecy VCardTool::parseSecrecy(const VCardLine &line) const
1513 {
1514  Secrecy secrecy;
1515 
1516  const QString value = line.value().toString().toLower();
1517  if (value == QLatin1String("public")) {
1518  secrecy.setType(Secrecy::Public);
1519  } else if (value == QLatin1String("private")) {
1520  secrecy.setType(Secrecy::Private);
1521  } else if (value == QLatin1String("confidential")) {
1522  secrecy.setType(Secrecy::Confidential);
1523  }
1524 
1525  return secrecy;
1526 }
1527 
1528 VCardLine VCardTool::createSecrecy(const Secrecy &secrecy) const
1529 {
1530  VCardLine line(QStringLiteral("CLASS"));
1531 
1532  int type = secrecy.type();
1533 
1534  if (type == Secrecy::Public) {
1535  line.setValue(QStringLiteral("PUBLIC"));
1536  } else if (type == Secrecy::Private) {
1537  line.setValue(QStringLiteral("PRIVATE"));
1538  } else if (type == Secrecy::Confidential) {
1539  line.setValue(QStringLiteral("CONFIDENTIAL"));
1540  }
1541 
1542  return line;
1543 }
1544 
1545 QStringList VCardTool::splitString(QChar sep, const QString &str) const
1546 {
1547  QStringList list;
1548  QString value(str);
1549 
1550  int start = 0;
1551  int pos = value.indexOf(sep, start);
1552 
1553  while (pos != -1) {
1554  if (pos == 0 || value[pos - 1] != QLatin1Char('\\')) {
1555  if (pos > start && pos <= value.length()) {
1556  list << value.mid(start, pos - start);
1557  } else {
1558  list << QString();
1559  }
1560 
1561  start = pos + 1;
1562  pos = value.indexOf(sep, start);
1563  } else {
1564  value.replace(pos - 1, 2, sep);
1565  pos = value.indexOf(sep, pos);
1566  }
1567  }
1568 
1569  int l = value.length() - 1;
1570  const QString mid = value.mid(start, l - start + 1);
1571  if (!mid.isEmpty()) {
1572  list << mid;
1573  } else {
1574  list << QString();
1575  }
1576 
1577  return list;
1578 }
1579 
1580 QString VCardTool::normalizeImppServiceType(const QString &serviceType) const
1581 {
1582  if (serviceType == QLatin1String("jabber")) {
1583  return QStringLiteral("xmpp");
1584  }
1585  if (serviceType == QLatin1String("yahoo")) {
1586  return QStringLiteral("ymsgr");
1587  }
1588  if (serviceType == QLatin1String("gadugadu")) {
1589  return QStringLiteral("gg");
1590  }
1591  return serviceType;
1592 }
void setFormattedName(const QString &formattedName)
Set formatted name.
Definition: addressee.cpp:620
Class that holds a FieldGroup for a contact.
Definition: fieldgroup.h:21
void setOffset(int offset)
Set time zone offset relative to UTC.
Definition: timezone.cpp:54
void setMailer(const QString &mailer)
Set mail client.
Definition: addressee.cpp:946
int toInt(bool *ok, int base) const const
int minute() const const
int indexOf(QChar ch, int from, Qt::CaseSensitivity cs) const const
QString type() const
Returns the type of this picture.
Definition: picture.cpp:197
void setTextData(const QString &data)
Sets text data.
Definition: key.cpp:128
void setNumber(const QString &number)
Sets the phone number.
typedef Iterator
Custom or IANA conform key.
Definition: key.h:38
void insertLang(const Lang &language)
Insert Language.
Definition: addressee.cpp:1678
bool isBinary() const
Returns whether the key contains binary or text data.
Definition: key.cpp:139
void setLocality(const QString &locality)
Sets the locality, e.g.
Definition: address.cpp:424
Type type() const
Returns the type, see Type.
Definition: key.cpp:154
QDateTime startOfDay(Qt::TimeSpec spec, int offsetSeconds) const const
QString name(const QVariant &location)
QString asprintf(const char *cformat,...)
void insertPhoneNumber(const PhoneNumber &phoneNumber)
Insert a phone number.
Definition: addressee.cpp:1717
QString toString(Qt::DateFormat format) const const
QString toString(Qt::DateFormat format) const const
Describes a relationship of an Addressee.
Definition: related.h:19
void append(const T &value)
QVector::iterator begin()
void setTimeZone(const TimeZone &timeZone)
Set time zone.
Definition: addressee.cpp:966
Class that holds a Role for a contact.
Definition: role.h:21
void setPhoto(const Picture &photo)
Set photo.
Definition: addressee.cpp:1325
void setSuffix(const QString &suffix)
Set honorific suffixes.
Definition: addressee.cpp:720
QByteArray data() const
Returns the raw data of this sound.
Definition: sound.cpp:124
Class that holds a Resource Locator.
void setUid(const QString &uid)
Set unique identifier.
Definition: addressee.cpp:404
QVector::const_iterator constEnd() const const
const T & at(int i) const const
int size() const const
Geographic position.
Definition: geo.h:24
Class that holds a Calendar Url (FBURL/CALADRURI/CALURI)
Definition: calendarurl.h:22
void setTime(const QTime &time)
bool contains(const QString &str, Qt::CaseSensitivity cs) const const
bool isEmpty() const const
bool isValid() const const
void setStreet(const QString &street)
Sets the street (including house number).
Definition: address.cpp:408
Type type() const
Returns the type.
Definition: secrecy.cpp:78
void setPrefix(const QString &prefix)
Set honorific prefixes.
Definition: addressee.cpp:700
QTime time() const const
void setLabel(const QString &label)
Sets the delivery label.
Definition: address.cpp:488
void setGeo(const Geo &geo)
Set geographic position.
Definition: address.cpp:536
QTime fromString(const QString &string, Qt::DateFormat format)
Personal Communication Service.
Definition: phonenumber.h:61
void setType(Type type)
Sets the type.
QString join(const QString &separator) const const
void setGivenName(const QString &givenName)
Set given name.
Definition: addressee.cpp:660
QString & remove(int position, int n)
typedef ConstIterator
void setDepartment(const QString &department)
Set department.
Definition: addressee.cpp:1159
Sound sound() const
Return sound.
Definition: addressee.cpp:1355
void setAdditionalName(const QString &additionalName)
Set additional names.
Definition: addressee.cpp:680
TypeFlag
Phone number types.
Definition: phonenumber.h:48
preferred address
Definition: address.h:72
void setLongitude(float longitude)
Sets the longitude.
Definition: geo.cpp:79
void insertEmail(const QString &email, bool preferred=false, const QMap< QString, QStringList > &param=QMap< QString, QStringList >())
Insert an email address.
Definition: addressee.cpp:1584
int size() const const
bool isEmpty() const
Returns true, if the sound object is empty.
Definition: sound.cpp:114
TimeSpec
T value(int i) const const
QVector< V > values(const QMultiHash< K, V > &c)
void setPath(const QString &path, QUrl::ParsingMode mode)
void setType(Type type)
Sets the type of address.
Definition: address.cpp:316
void setCategories(const QStringList &category)
Set categories to given value.
Definition: addressee.cpp:2082
Preferred number.
Definition: phonenumber.h:52
QDate fromString(const QString &string, Qt::DateFormat format)
int count(const T &value) const const
Class that holds a ClientPidMap for a contact.
Definition: clientpidmap.h:21
void append(const T &value)
int offset() const
Return offset in minutes relative to UTC.
Definition: timezone.cpp:60
void setSortString(const QString &sortString)
Set sort string.
Definition: addressee.cpp:1239
PostalAddress address(const QVariant &location)
QString textData() const
Returns the text data.
Definition: key.cpp:134
QMapIterator::Item next()
Type type(const QSqlDatabase &db)
QString label(StandardShortcut id)
void setFamilyName(const QString &familyName)
Set family name.
Definition: addressee.cpp:640
GeoCoordinates geo(const QVariant &location)
CaseInsensitive
bool isEmpty() const const
bool isEmpty() const const
int removeAll(const T &value)
bool startsWith(const QString &s, Qt::CaseSensitivity cs) const const
home address
Definition: address.h:70
A class to store an encryption key.
Definition: key.h:21
void setScheme(const QString &scheme)
QStringList split(const QString &sep, QString::SplitBehavior behavior, Qt::CaseSensitivity cs) const const
bool isValid() const const
void setRegion(const QString &region)
Sets the region, e.g.
Definition: address.cpp:440
QTime addSecs(int s) const const
typedef Iterator
void setType(Type type)
Sets the type.
Definition: secrecy.cpp:73
QDate addYears(int nyears) const const
Class that holds a IMPP for a contact.
Definition: impp.h:27
QString right(int n) const const
QLatin1String left(int length) const const
void setLatitude(float latitude)
Sets the latitude.
Definition: geo.cpp:63
A class to store a picture of an addressee.
Definition: picture.h:26
int hour() const const
QList::iterator end()
QString toLower() const const
void setData(const QByteArray &data)
Sets the raw data of the sound.
Definition: sound.cpp:103
QByteArray rawData() const
Returns the raw data of this picture.
Definition: picture.cpp:184
bool contains(QChar ch, Qt::CaseSensitivity cs) const const
KeepEmptyParts
void setExtended(const QString &extended)
Sets the extended address information.
Definition: address.cpp:392
Qt::TimeSpec timeSpec() const const
void setProductId(const QString &productId)
Set product identifier.
Definition: addressee.cpp:1199
QStringRef midRef(int position, int n) const const
char toLatin1() const const
void setPostalCode(const QString &code)
Sets the postal code.
Definition: address.cpp:456
QByteArray binaryData() const
Returns the binary data.
Definition: key.cpp:123
void insertCustom(const QString &app, const QString &name, const QString &value)
Insert custom entry.
Definition: addressee.cpp:2245
QString & replace(int position, int n, QChar after)
const QList< QKeySequence > & end()
void insertKey(const Key &key)
Insert a key.
Definition: addressee.cpp:1800
QVector::const_iterator constBegin() const const
Class that holds a Sound clip for a contact.
Definition: sound.h:45
QString url() const
Returns the location URL of this sound.
Definition: sound.cpp:119
QString mid(int position, int n) const const
QDate date() const const
Pretty Good Privacy key.
Definition: key.h:37
void setNote(const QString &note)
Set note.
Definition: addressee.cpp:1179
Postal address information.
Definition: address.h:28
void setPostOfficeBox(const QString &postOfficeBox)
Sets the post office box.
Definition: address.cpp:376
Class that holds a NickName for a contact.
Definition: nickname.h:21
void setCountry(const QString &country)
Sets the country.
Definition: address.cpp:472
void setRawData(const QByteArray &rawData, const QString &type)
Sets the raw data of the picture.
Definition: picture.cpp:157
void setUrl(const QString &url)
Sets a URL for the location of the picture file.
Definition: picture.cpp:129
void setGeo(const Geo &geo)
Set geographic position.
Definition: addressee.cpp:986
const QChar at(int position) const const
void setRevision(const QDateTime &revision)
Set revision date.
Definition: addressee.cpp:1219
Class that holds a Language for a contact.
Definition: lang.h:21
X509 key.
Definition: key.h:36
typedef ConstIterator
Describes the confidentiality of an addressee.
Definition: secrecy.h:18
void setLogo(const Picture &logo)
Set logo.
Definition: addressee.cpp:1305
void setBirthday(const QDateTime &birthday, bool withTime=true)
Set birthday (date and time).
Definition: addressee.cpp:791
Class that holds a Gender for a contact.
Definition: gender.h:19
Class that holds a Title for a contact.
Definition: title.h:21
int length() const const
QString left(int n) const const
QString fromLatin1(const char *str, int size)
bool isValid() const
Return, if this time zone object is valid.
Definition: timezone.cpp:65
void setType(Type type)
Sets the type.
Definition: key.cpp:144
void setCustomTypeString(const QString &type)
Sets custom type string.
Definition: key.cpp:149
bool isIntern() const
Returns whether the sound is described by a URL (extern) or by the raw data (intern).
Definition: sound.cpp:109
address book entry
Definition: addressee.h:69
international
Definition: address.h:67
Class that holds a Organization for a contact.
Definition: org.h:21
Time zone information.
Definition: timezone.h:22
void setName(const QString &name)
Set name.
Definition: addressee.cpp:424
TypeFlag
Address types:
Definition: address.h:65
QList::const_iterator constEnd() const const
QList::const_iterator constBegin() const const
address at work
Definition: address.h:71
int offsetFromUtc() const const
int year() const const
int compare(const QString &other, Qt::CaseSensitivity cs) const const
void setUrl(const QString &url)
Sets a URL for the location of the sound file.
Definition: sound.cpp:97
QVector::iterator end()
QString customTypeString() const
Returns the custom type string.
Definition: key.cpp:159
QList::iterator begin()
void setSecrecy(const Secrecy &secrecy)
Set security class.
Definition: addressee.cpp:1285
Phonenumber information.
Definition: phonenumber.h:28
void setBinaryData(const QByteArray &data)
Sets binary data.
Definition: key.cpp:117
void insertAddress(const Address &address)
Insert an address.
Definition: addressee.cpp:1978
Types types(const QStringList &mimeTypes)
void setSound(const Sound &sound)
Set sound.
Definition: addressee.cpp:1345
Picture logo() const
Return logo.
Definition: addressee.cpp:1315
This file is part of the KDE documentation.
Documentation copyright © 1996-2021 The KDE developers.
Generated on Sun Sep 26 2021 22:55:57 by doxygen 1.8.11 written by Dimitri van Heesch, © 1997-2006

KDE's Doxygen guidelines are available online.