File indexing completed on 2023-09-24 04:03:51
0001 /* 0002 This file is part of the KContacts framework. 0003 SPDX-FileCopyrightText: 2003 Helge Deller <deller@kde.org> 0004 0005 SPDX-License-Identifier: LGPL-2.0-or-later 0006 */ 0007 0008 /* 0009 Useful links: 0010 - http://tldp.org/HOWTO/LDAP-Implementation-HOWTO/schemas.html 0011 - http://www.faqs.org/rfcs/rfc2849.html 0012 0013 Not yet handled items: 0014 - objectclass microsoftaddressbook 0015 - info, 0016 - initials, 0017 - otherfacsimiletelephonenumber, 0018 - otherpager, 0019 - physicaldeliveryofficename, 0020 */ 0021 0022 #include "ldifconverter.h" 0023 #include "address.h" 0024 #include "kcontacts_debug.h" 0025 #include "vcardconverter.h" 0026 0027 #include "ldif_p.h" 0028 0029 #include <KCountry> 0030 #include <KLocalizedString> 0031 0032 #include <QIODevice> 0033 #include <QStringList> 0034 #if QT_VERSION < QT_VERSION_CHECK(6, 0, 0) 0035 #include <QTextCodec> 0036 #endif 0037 #include <QTextStream> 0038 0039 using namespace KContacts; 0040 0041 /* internal functions - do not use !! */ 0042 0043 namespace KContacts 0044 { 0045 /** 0046 @internal 0047 0048 Evaluates @p fieldname and sets the @p value at the addressee or the address 0049 objects when appropriate. 0050 0051 @param a The addressee to store information into 0052 @param homeAddr The home address to store respective information into 0053 @param workAddr The work address to store respective information into 0054 @param fieldname LDIF field name to evaluate 0055 @param value The value of the field addressed by @p fieldname 0056 */ 0057 void evaluatePair(Addressee &a, 0058 Address &homeAddr, 0059 Address &workAddr, 0060 QString &fieldname, 0061 QString &value, 0062 int &birthday, 0063 int &birthmonth, 0064 int &birthyear, 0065 ContactGroup &contactGroup); 0066 } 0067 0068 /* generate LDIF stream */ 0069 0070 static void ldif_out(QTextStream &t, const QString &formatStr, const QString &value) 0071 { 0072 if (value.isEmpty()) { 0073 return; 0074 } 0075 0076 const QByteArray txt = Ldif::assembleLine(formatStr, value, 72); 0077 0078 // write the string 0079 t << QString::fromUtf8(txt) << "\n"; 0080 } 0081 0082 bool LDIFConverter::addresseeAndContactGroupToLDIF(const AddresseeList &addrList, const ContactGroup::List &contactGroupList, QString &str) 0083 { 0084 bool result = addresseeToLDIF(addrList, str); 0085 if (!contactGroupList.isEmpty()) { 0086 result = (contactGroupToLDIF(contactGroupList, str) || result); // order matters 0087 } 0088 return result; 0089 } 0090 0091 bool LDIFConverter::contactGroupToLDIF(const ContactGroup &contactGroup, QString &str) 0092 { 0093 if (contactGroup.dataCount() <= 0) { 0094 return false; 0095 } 0096 QTextStream t(&str, QIODevice::WriteOnly | QIODevice::Append); 0097 #if QT_VERSION < QT_VERSION_CHECK(6, 0, 0) 0098 t.setCodec(QTextCodec::codecForName("UTF-8")); 0099 #endif 0100 0101 t << "objectclass: top\n"; 0102 t << "objectclass: groupOfNames\n"; 0103 0104 for (int i = 0; i < contactGroup.dataCount(); ++i) { 0105 const ContactGroup::Data &data = contactGroup.data(i); 0106 const QString value = QStringLiteral("cn=%1,mail=%2").arg(data.name(), data.email()); 0107 ldif_out(t, QStringLiteral("member"), value); 0108 } 0109 0110 t << "\n"; 0111 return true; 0112 } 0113 0114 bool LDIFConverter::contactGroupToLDIF(const ContactGroup::List &contactGroupList, QString &str) 0115 { 0116 if (contactGroupList.isEmpty()) { 0117 return false; 0118 } 0119 0120 bool result = true; 0121 for (const ContactGroup &group : contactGroupList) { 0122 result = (contactGroupToLDIF(group, str) || result); // order matters 0123 } 0124 return result; 0125 } 0126 0127 bool LDIFConverter::addresseeToLDIF(const AddresseeList &addrList, QString &str) 0128 { 0129 if (addrList.isEmpty()) { 0130 return false; 0131 } 0132 0133 bool result = true; 0134 for (const Addressee &addr : addrList) { 0135 result = (addresseeToLDIF(addr, str) || result); // order matters 0136 } 0137 return result; 0138 } 0139 0140 static QString countryName(const QString &isoCodeOrName) 0141 { 0142 const auto c = KCountry::fromAlpha2(isoCodeOrName); 0143 return c.isValid() ? c.name() : isoCodeOrName; 0144 } 0145 0146 bool LDIFConverter::addresseeToLDIF(const Addressee &addr, QString &str) 0147 { 0148 if (addr.isEmpty()) { 0149 return false; 0150 } 0151 0152 QTextStream t(&str, QIODevice::WriteOnly | QIODevice::Append); 0153 #if QT_VERSION < QT_VERSION_CHECK(6, 0, 0) 0154 t.setCodec(QTextCodec::codecForName("UTF-8")); 0155 #endif 0156 0157 const Address homeAddr = addr.address(Address::Home); 0158 const Address workAddr = addr.address(Address::Work); 0159 0160 ldif_out(t, QStringLiteral("dn"), QStringLiteral("cn=%1,mail=%2").arg(addr.formattedName().simplified(), addr.preferredEmail())); 0161 t << "objectclass: top\n"; 0162 t << "objectclass: person\n"; 0163 t << "objectclass: organizationalPerson\n"; 0164 0165 ldif_out(t, QStringLiteral("givenname"), addr.givenName()); 0166 ldif_out(t, QStringLiteral("sn"), addr.familyName()); 0167 ldif_out(t, QStringLiteral("cn"), addr.formattedName().simplified()); 0168 ldif_out(t, QStringLiteral("uid"), addr.uid()); 0169 ldif_out(t, QStringLiteral("nickname"), addr.nickName()); 0170 ldif_out(t, QStringLiteral("xmozillanickname"), addr.nickName()); 0171 ldif_out(t, QStringLiteral("mozillanickname"), addr.nickName()); 0172 0173 ldif_out(t, QStringLiteral("mail"), addr.preferredEmail()); 0174 const QStringList emails = addr.emails(); 0175 const int numEmails = emails.count(); 0176 for (int i = 1; i < numEmails; ++i) { 0177 if (i == 0) { 0178 // nothing 0179 } else if (i == 1) { 0180 ldif_out(t, QStringLiteral("mozillasecondemail"), emails[1]); 0181 } else { 0182 ldif_out(t, QStringLiteral("othermailbox"), emails[i]); 0183 } 0184 } 0185 // ldif_out( t, "mozilla_AIMScreenName: %1\n", "screen_name" ); 0186 0187 ldif_out(t, QStringLiteral("telephonenumber"), addr.phoneNumber(PhoneNumber::Work).number()); 0188 ldif_out(t, QStringLiteral("facsimiletelephonenumber"), addr.phoneNumber(PhoneNumber::Fax).number()); 0189 ldif_out(t, QStringLiteral("homephone"), addr.phoneNumber(PhoneNumber::Home).number()); 0190 ldif_out(t, QStringLiteral("mobile"), 0191 addr.phoneNumber(PhoneNumber::Cell).number()); // Netscape 7 0192 ldif_out(t, QStringLiteral("cellphone"), 0193 addr.phoneNumber(PhoneNumber::Cell).number()); // Netscape 4.x 0194 ldif_out(t, QStringLiteral("pager"), addr.phoneNumber(PhoneNumber::Pager).number()); 0195 ldif_out(t, QStringLiteral("pagerphone"), addr.phoneNumber(PhoneNumber::Pager).number()); 0196 0197 ldif_out(t, QStringLiteral("streethomeaddress"), homeAddr.street()); 0198 ldif_out(t, QStringLiteral("postalcode"), workAddr.postalCode()); 0199 ldif_out(t, QStringLiteral("postofficebox"), workAddr.postOfficeBox()); 0200 0201 QStringList streets = homeAddr.street().split(QLatin1Char('\n')); 0202 const int numberOfStreets(streets.count()); 0203 if (numberOfStreets > 0) { 0204 ldif_out(t, QStringLiteral("homepostaladdress"), streets.at(0)); // Netscape 7 0205 } 0206 if (numberOfStreets > 1) { 0207 ldif_out(t, QStringLiteral("mozillahomepostaladdress2"), streets.at(1)); // Netscape 7 0208 } 0209 ldif_out(t, QStringLiteral("mozillahomelocalityname"), homeAddr.locality()); // Netscape 7 0210 ldif_out(t, QStringLiteral("mozillahomestate"), homeAddr.region()); 0211 ldif_out(t, QStringLiteral("mozillahomepostalcode"), homeAddr.postalCode()); 0212 ldif_out(t, QStringLiteral("mozillahomecountryname"), countryName(homeAddr.country())); 0213 ldif_out(t, QStringLiteral("locality"), workAddr.locality()); 0214 ldif_out(t, QStringLiteral("streetaddress"), workAddr.street()); // Netscape 4.x 0215 0216 streets = workAddr.street().split(QLatin1Char('\n')); 0217 const int streetsCount = streets.count(); 0218 if (streetsCount > 0) { 0219 ldif_out(t, QStringLiteral("street"), streets.at(0)); 0220 } 0221 if (streetsCount > 1) { 0222 ldif_out(t, QStringLiteral("mozillaworkstreet2"), streets.at(1)); 0223 } 0224 ldif_out(t, QStringLiteral("countryname"), countryName(workAddr.country())); 0225 ldif_out(t, QStringLiteral("l"), workAddr.locality()); 0226 ldif_out(t, QStringLiteral("c"), countryName(workAddr.country())); 0227 ldif_out(t, QStringLiteral("st"), workAddr.region()); 0228 0229 ldif_out(t, QStringLiteral("title"), addr.title()); 0230 ldif_out(t, QStringLiteral("vocation"), addr.prefix()); 0231 ldif_out(t, QStringLiteral("ou"), addr.role()); 0232 ldif_out(t, QStringLiteral("o"), addr.organization()); 0233 ldif_out(t, QStringLiteral("organization"), addr.organization()); 0234 ldif_out(t, QStringLiteral("organizationname"), addr.organization()); 0235 0236 // Compatibility with older kabc versions. 0237 if (!addr.department().isEmpty()) { 0238 ldif_out(t, QStringLiteral("department"), addr.department()); 0239 } else { 0240 ldif_out(t, QStringLiteral("department"), addr.custom(QStringLiteral("KADDRESSBOOK"), QStringLiteral("X-Department"))); 0241 } 0242 0243 ldif_out(t, QStringLiteral("workurl"), addr.url().url().toDisplayString()); 0244 ldif_out(t, QStringLiteral("homeurl"), addr.url().url().toDisplayString()); 0245 ldif_out(t, QStringLiteral("mozillahomeurl"), addr.url().url().toDisplayString()); 0246 0247 ldif_out(t, QStringLiteral("description"), addr.note()); 0248 if (addr.revision().isValid()) { 0249 ldif_out(t, QStringLiteral("modifytimestamp"), dateToVCardString(addr.revision())); 0250 } 0251 0252 const QDate birthday = addr.birthday().date(); 0253 if (birthday.isValid()) { 0254 const int year = birthday.year(); 0255 if (year > 0) { 0256 ldif_out(t, QStringLiteral("birthyear"), QString::number(year)); 0257 } 0258 ldif_out(t, QStringLiteral("birthmonth"), QString::number(birthday.month())); 0259 ldif_out(t, QStringLiteral("birthday"), QString::number(birthday.day())); 0260 } 0261 0262 t << "\n"; 0263 0264 return true; 0265 } 0266 0267 /* convert from LDIF stream */ 0268 bool LDIFConverter::LDIFToAddressee(const QString &str, AddresseeList &addrList, ContactGroup::List &contactGroupList, const QDateTime &dt) 0269 { 0270 if (str.isEmpty()) { 0271 return true; 0272 } 0273 0274 bool endldif = false; 0275 bool end = false; 0276 Ldif ldif; 0277 Ldif::ParseValue ret; 0278 Addressee a; 0279 Address homeAddr; 0280 Address workAddr; 0281 int birthday = -1; 0282 int birthmonth = -1; 0283 int birthyear = -1; 0284 ContactGroup contactGroup; 0285 ldif.setLdif(str.toLatin1()); 0286 QDateTime qdt = dt; 0287 if (!qdt.isValid()) { 0288 qdt = QDateTime::currentDateTime(); 0289 } 0290 a.setRevision(qdt); 0291 homeAddr = Address(Address::Home); 0292 workAddr = Address(Address::Work); 0293 0294 do { 0295 ret = ldif.nextItem(); 0296 switch (ret) { 0297 case Ldif::Item: { 0298 QString fieldname = ldif.attr().toLower(); 0299 QString value = QString::fromUtf8(ldif.value()); 0300 evaluatePair(a, homeAddr, workAddr, fieldname, value, birthday, birthmonth, birthyear, contactGroup); 0301 break; 0302 } 0303 case Ldif::EndEntry: 0304 if (contactGroup.count() == 0) { 0305 // if the new address is not empty, append it 0306 QDate birthDate(birthyear, birthmonth, birthday); 0307 if (birthDate.isValid()) { 0308 a.setBirthday(birthDate); 0309 } 0310 0311 if (!a.formattedName().isEmpty() || !a.name().isEmpty() || !a.familyName().isEmpty()) { 0312 if (!homeAddr.isEmpty()) { 0313 a.insertAddress(homeAddr); 0314 } 0315 if (!workAddr.isEmpty()) { 0316 a.insertAddress(workAddr); 0317 } 0318 addrList.append(a); 0319 } 0320 } else { 0321 contactGroupList.append(contactGroup); 0322 } 0323 a = Addressee(); 0324 contactGroup = ContactGroup(); 0325 a.setRevision(qdt); 0326 homeAddr = Address(Address::Home); 0327 workAddr = Address(Address::Work); 0328 break; 0329 case Ldif::MoreData: 0330 if (endldif) { 0331 end = true; 0332 } else { 0333 ldif.endLdif(); 0334 endldif = true; 0335 break; 0336 } 0337 default: 0338 break; 0339 } 0340 } while (!end); 0341 0342 return true; 0343 } 0344 0345 void KContacts::evaluatePair(Addressee &a, 0346 Address &homeAddr, 0347 Address &workAddr, 0348 QString &fieldname, 0349 QString &value, 0350 int &birthday, 0351 int &birthmonth, 0352 int &birthyear, 0353 ContactGroup &contactGroup) 0354 { 0355 if (fieldname == QLatin1String("dn")) { // ignore 0356 return; 0357 } 0358 0359 if (fieldname.startsWith(QLatin1Char('#'))) { 0360 return; 0361 } 0362 0363 if (fieldname.isEmpty() && !a.note().isEmpty()) { 0364 // some LDIF export filters are broken and add additional 0365 // comments on stand-alone lines. Just add them to the notes for now. 0366 a.setNote(a.note() + QLatin1Char('\n') + value); 0367 return; 0368 } 0369 0370 if (fieldname == QLatin1String("givenname")) { 0371 a.setGivenName(value); 0372 return; 0373 } 0374 0375 if (fieldname == QLatin1String("xmozillanickname") // 0376 || fieldname == QLatin1String("nickname") // 0377 || fieldname == QLatin1String("mozillanickname")) { 0378 a.setNickName(value); 0379 return; 0380 } 0381 0382 if (fieldname == QLatin1String("sn")) { 0383 a.setFamilyName(value); 0384 return; 0385 } 0386 0387 if (fieldname == QLatin1String("uid")) { 0388 a.setUid(value); 0389 return; 0390 } 0391 if (fieldname == QLatin1String("mail") // 0392 || fieldname == QLatin1String("mozillasecondemail") /* mozilla */ 0393 || fieldname == QLatin1String("othermailbox") /*TheBat!*/) { 0394 if (a.emails().indexOf(value) == -1) { 0395 a.addEmail(value); 0396 } 0397 return; 0398 } 0399 0400 if (fieldname == QLatin1String("title")) { 0401 a.setTitle(value); 0402 return; 0403 } 0404 0405 if (fieldname == QLatin1String("vocation")) { 0406 a.setPrefix(value); 0407 return; 0408 } 0409 0410 if (fieldname == QLatin1String("cn")) { 0411 a.setFormattedName(value); 0412 return; 0413 } 0414 0415 if (fieldname == QLatin1Char('o') || fieldname == QLatin1String("organization") // Exchange 0416 || fieldname == QLatin1String("organizationname")) { // Exchange 0417 a.setOrganization(value); 0418 return; 0419 } 0420 0421 // clang-format off 0422 if (fieldname == QLatin1String("description") 0423 || fieldname == QLatin1String("mozillacustom1") 0424 || fieldname == QLatin1String("mozillacustom2") 0425 || fieldname == QLatin1String("mozillacustom3") 0426 || fieldname == QLatin1String("mozillacustom4") 0427 || fieldname == QLatin1String("custom1") 0428 || fieldname == QLatin1String("custom2") 0429 || fieldname == QLatin1String("custom3") 0430 || fieldname == QLatin1String("custom4")) { 0431 if (!a.note().isEmpty()) { 0432 a.setNote(a.note() + QLatin1Char('\n')); 0433 } 0434 a.setNote(a.note() + value); 0435 return; 0436 } 0437 // clang-format on 0438 0439 if (fieldname == QLatin1String("homeurl") // 0440 || fieldname == QLatin1String("workurl") // 0441 || fieldname == QLatin1String("mozillahomeurl")) { 0442 if (a.url().url().isEmpty()) { 0443 ResourceLocatorUrl url; 0444 url.setUrl(QUrl(value)); 0445 a.setUrl(url); 0446 return; 0447 } 0448 if (a.url().url().toDisplayString() == QUrl(value).toDisplayString()) { 0449 return; 0450 } 0451 // TODO: current version of kabc only supports one URL. 0452 // TODO: change this with KDE 4 0453 } 0454 0455 if (fieldname == QLatin1String("homephone")) { 0456 a.insertPhoneNumber(PhoneNumber(value, PhoneNumber::Home)); 0457 return; 0458 } 0459 0460 if (fieldname == QLatin1String("telephonenumber")) { 0461 a.insertPhoneNumber(PhoneNumber(value, PhoneNumber::Work)); 0462 return; 0463 } 0464 if (fieldname == QLatin1String("mobile") /* mozilla/Netscape 7 */ 0465 || fieldname == QLatin1String("cellphone")) { 0466 a.insertPhoneNumber(PhoneNumber(value, PhoneNumber::Cell)); 0467 return; 0468 } 0469 0470 if (fieldname == QLatin1String("pager") // mozilla 0471 || fieldname == QLatin1String("pagerphone")) { // mozilla 0472 a.insertPhoneNumber(PhoneNumber(value, PhoneNumber::Pager)); 0473 return; 0474 } 0475 0476 if (fieldname == QLatin1String("facsimiletelephonenumber")) { 0477 a.insertPhoneNumber(PhoneNumber(value, PhoneNumber::Fax)); 0478 return; 0479 } 0480 0481 if (fieldname == QLatin1String("xmozillaanyphone")) { // mozilla 0482 a.insertPhoneNumber(PhoneNumber(value, PhoneNumber::Work)); 0483 return; 0484 } 0485 0486 if (fieldname == QLatin1String("streethomeaddress") // 0487 || fieldname == QLatin1String("mozillahomestreet")) { // thunderbird 0488 homeAddr.setStreet(value); 0489 return; 0490 } 0491 0492 if (fieldname == QLatin1String("street") // 0493 || fieldname == QLatin1String("postaladdress")) { // mozilla 0494 workAddr.setStreet(value); 0495 return; 0496 } 0497 if (fieldname == QLatin1String("mozillapostaladdress2") // 0498 || fieldname == QLatin1String("mozillaworkstreet2")) { // mozilla 0499 workAddr.setStreet(workAddr.street() + QLatin1Char('\n') + value); 0500 return; 0501 } 0502 0503 if (fieldname == QLatin1String("postalcode")) { 0504 workAddr.setPostalCode(value); 0505 return; 0506 } 0507 0508 if (fieldname == QLatin1String("postofficebox")) { 0509 workAddr.setPostOfficeBox(value); 0510 return; 0511 } 0512 0513 if (fieldname == QLatin1String("homepostaladdress")) { // Netscape 7 0514 homeAddr.setStreet(value); 0515 return; 0516 } 0517 0518 if (fieldname == QLatin1String("mozillahomepostaladdress2")) { // mozilla 0519 homeAddr.setStreet(homeAddr.street() + QLatin1Char('\n') + value); 0520 return; 0521 } 0522 0523 if (fieldname == QLatin1String("mozillahomelocalityname")) { // mozilla 0524 homeAddr.setLocality(value); 0525 return; 0526 } 0527 0528 if (fieldname == QLatin1String("mozillahomestate")) { // mozilla 0529 homeAddr.setRegion(value); 0530 return; 0531 } 0532 0533 if (fieldname == QLatin1String("mozillahomepostalcode")) { // mozilla 0534 homeAddr.setPostalCode(value); 0535 return; 0536 } 0537 0538 if (fieldname == QLatin1String("mozillahomecountryname")) { // mozilla 0539 if (value.length() <= 2) { 0540 value = countryName(value); 0541 } 0542 homeAddr.setCountry(value); 0543 return; 0544 } 0545 0546 if (fieldname == QLatin1String("locality")) { 0547 workAddr.setLocality(value); 0548 return; 0549 } 0550 0551 if (fieldname == QLatin1String("streetaddress")) { // Netscape 4.x 0552 workAddr.setStreet(value); 0553 return; 0554 } 0555 0556 if (fieldname == QLatin1String("countryname") // 0557 || fieldname == QLatin1Char('c')) { // mozilla 0558 if (value.length() <= 2) { 0559 value = countryName(value); 0560 } 0561 workAddr.setCountry(value); 0562 return; 0563 } 0564 0565 if (fieldname == QLatin1Char('l')) { // mozilla 0566 workAddr.setLocality(value); 0567 return; 0568 } 0569 0570 if (fieldname == QLatin1String("st")) { 0571 workAddr.setRegion(value); 0572 return; 0573 } 0574 0575 if (fieldname == QLatin1String("ou")) { 0576 a.setRole(value); 0577 return; 0578 } 0579 0580 if (fieldname == QLatin1String("department")) { 0581 a.setDepartment(value); 0582 return; 0583 } 0584 0585 if (fieldname == QLatin1String("member")) { 0586 // this is a mozilla list member (cn=xxx, mail=yyy) 0587 const QStringList list = value.split(QLatin1Char(',')); 0588 QString name; 0589 QString email; 0590 0591 const QLatin1String cnTag("cn="); 0592 const QLatin1String mailTag("mail="); 0593 for (const auto &str : list) { 0594 if (str.startsWith(cnTag)) { 0595 name = QStringView(str).mid(cnTag.size()).trimmed().toString(); 0596 } else if (str.startsWith(mailTag)) { 0597 email = QStringView(str).mid(mailTag.size()).trimmed().toString(); 0598 } 0599 } 0600 0601 if (!name.isEmpty() && !email.isEmpty()) { 0602 email = QLatin1String(" <") + email + QLatin1Char('>'); 0603 } 0604 ContactGroup::Data data; 0605 data.setEmail(email); 0606 data.setName(name); 0607 contactGroup.append(data); 0608 return; 0609 } 0610 0611 if (fieldname == QLatin1String("modifytimestamp")) { 0612 if (value == QLatin1String("0Z")) { // ignore 0613 return; 0614 } 0615 QDateTime dt = VCardStringToDate(value); 0616 if (dt.isValid()) { 0617 a.setRevision(dt); 0618 return; 0619 } 0620 } 0621 0622 if (fieldname == QLatin1String("display-name")) { 0623 contactGroup.setName(value); 0624 return; 0625 } 0626 0627 if (fieldname == QLatin1String("objectclass")) { // ignore 0628 return; 0629 } 0630 0631 if (fieldname == QLatin1String("birthyear")) { 0632 bool ok; 0633 birthyear = value.toInt(&ok); 0634 if (!ok) { 0635 birthyear = -1; 0636 } 0637 return; 0638 } 0639 if (fieldname == QLatin1String("birthmonth")) { 0640 birthmonth = value.toInt(); 0641 return; 0642 } 0643 if (fieldname == QLatin1String("birthday")) { 0644 birthday = value.toInt(); 0645 return; 0646 } 0647 if (fieldname == QLatin1String("xbatbirthday")) { 0648 #if QT_VERSION >= QT_VERSION_CHECK(6, 0, 0) 0649 const QStringView str{value}; 0650 #else 0651 const QStringRef str{&value}; 0652 #endif 0653 QDate dt(str.mid(0, 4).toInt(), str.mid(4, 2).toInt(), str.mid(6, 2).toInt()); 0654 if (dt.isValid()) { 0655 a.setBirthday(dt); 0656 } 0657 return; 0658 } 0659 qCWarning(KCONTACTS_LOG) << QStringLiteral("LDIFConverter: Unknown field for '%1': '%2=%3'\n").arg(a.formattedName(), fieldname, value); 0660 }