QByteArray contactToXML(const ContactPtr& contact) { QByteArray output; QStringList parsedCustoms; /* Name */ output.append("<gd:name>"); if (!contact->givenName().isEmpty()) { output.append("<gd:givenName>").append(Qt::escape(contact->givenName()).toUtf8()).append("</gd:givenName>"); } if (!contact->familyName().isEmpty()) { output.append("<gd:familyName>").append(Qt::escape(contact->familyName()).toUtf8()).append("</gd:familyName>"); } if (!contact->assembledName().isEmpty()) { output.append("<gd:fullName>").append(Qt::escape(contact->assembledName()).toUtf8()).append("</gd:fullName>"); } if (!contact->additionalName().isEmpty()) { output.append("<gd:additionalName>").append(Qt::escape(contact->additionalName()).toUtf8()).append("</gd:additionalName>"); } if (!contact->prefix().isEmpty()) { output.append("<gd:namePrefix>").append(Qt::escape(contact->prefix()).toUtf8()).append("</gd:namePrefix>"); } if (!contact->suffix().isEmpty()) { output.append("<gd:nameSuffix>").append(Qt::escape(contact->suffix()).toUtf8()).append("</gd:nameSuffix>"); } output.append("</gd:name>"); /* Notes */ if (!contact->note().isEmpty()) { output.append("<atom:content type='text'>").append(Qt::escape(contact->note()).toUtf8()).append("</atom:content>"); } /* Organization (work) */ QByteArray org; const QString office = contact->office(); if (!contact->organization().isEmpty()) { org.append("<gd:orgName>").append(Qt::escape(contact->organization()).toUtf8()).append("</gd:orgName>"); } if (!contact->department().isEmpty()) { org.append("<gd:orgDepartment>").append(Qt::escape(contact->department()).toUtf8()).append("</gd:orgDepartment>"); } if (!contact->title().isEmpty()) { org.append("<gd:orgTitle>").append(Qt::escape(contact->title()).toUtf8()).append("</gd:orgTitle>"); } if (!office.isEmpty()) { org.append("<gd:where>").append(Qt::escape(office).toUtf8()).append("</gd:where>"); parsedCustoms << QStringLiteral("KADDRESSBOOK-X-Office"); } if (!org.isEmpty()) { output.append("<gd:organization rel=\"http://schemas.google.com/g/2005#work\">").append(org).append("</gd:organization>"); } /* Nickname */ if (!contact->nickName().isEmpty()) { output.append("<gContact:nickname>").append(Qt::escape(contact->nickName()).toUtf8()).append("</gContact:nickname>"); } /* Occupation */ if (!contact->profession().isEmpty()) { output.append("<gContact:occupation>").append(Qt::escape(contact->profession()).toUtf8()).append("</gContact:occupation>"); parsedCustoms << QStringLiteral("KADDRESSBOOK-X-Profession"); } /* Spouse */ const QString spouse = contact->spousesName(); if (!spouse.isEmpty()) { output.append("<gContact:relation rel=\"spouse\">").append(Qt::escape(spouse).toUtf8()).append("</gContact:relation>"); parsedCustoms << QStringLiteral("KADDRESSBOOK-X-SpousesName"); } /* Manager */ const QString manager = contact->managersName(); if (!manager.isEmpty()) { output.append("<gContact:relation rel=\"manager\">").append(Qt::escape(manager).toUtf8()).append("</gContact:relation>"); parsedCustoms << QStringLiteral("KADDRESSBOOK-X-ManagersName"); } /* Assistant */ const QString assistant = contact->assistantsName(); if (!assistant.isEmpty()) { output.append("<gContact:relation rel=\"assistant\">").append(Qt::escape(assistant).toUtf8()).append("</gContact:relation>"); parsedCustoms << QStringLiteral("KADDRESSBOOK-X-AssistantsName"); } /* Anniversary */ const QString anniversary = contact->anniversary(); if (!anniversary.isEmpty()) { output.append("<gContact:event rel=\"anniversary\"><gd:when startTime=\"").append(Qt::escape(anniversary).toUtf8()).append("\" /></gContact:event>"); parsedCustoms << QStringLiteral("KADDRESSBOOK-X-Anniversary"); } /* Homepage */ if (!contact->url().url().isEmpty()) { output.append("<gContact:website rel=\"home-page\" href=\"").append(Qt::escape(contact->url().toString()).toUtf8()).append("\" />"); } /* Blog */ const QString blog = contact->blogFeed(); if (!blog.isEmpty()) { output.append("<gContact:website rel=\"blog\" href=\"").append(Qt::escape(blog).toUtf8()).append("\" />"); parsedCustoms << QStringLiteral("KADDRESSBOOK-BlogFeed"); } /* Emails */ Q_FOREACH(const QString &email, contact->emails()) { output.append("<gd:email rel='http://schemas.google.com/g/2005#home' address='").append(Qt::escape(email).toUtf8()).append("' />"); } /* IMs */ const QString im_str = QStringLiteral("<gd:im address=\"%1\" protocol=\"%2\" rel=\"http://schemas.google.com/g/2005#other\" primary=\"%3\"/>"); Q_FOREACH(const QString &im, contact->customs()) { if (im.startsWith(QLatin1String("messaging/"))) { QString key = im.left(im.indexOf(QLatin1Char(':'))); QString value = im.mid(im.indexOf(QLatin1Char(':')) + 1); QString proto = key.mid(10); proto.chop(4); bool primary = (contact->custom(QStringLiteral("KADDRESSBOOK"), QStringLiteral("X-IMAddress")) == value); output.append(im_str.arg(value, Contact::IMProtocolNameToScheme(proto), (primary ? QStringLiteral("true") : QStringLiteral("false"))).toUtf8()); parsedCustoms << key; /* X-messaging is probably a new key (?) used by KAddressbook when importing * contacts from vCard. */ } else if (im.startsWith(QLatin1String("X-messaging"))) { const QString key = im.left(im.indexOf(QLatin1Char(':'))); const QString value = im.mid(im.indexOf(QLatin1Char(':')) + 1); QString proto = key.mid(12); /* strlen("X-messaging/") */ if (proto.endsWith(QLatin1String("-All"))) { proto.chop(4); } output.append(im_str.arg(value, proto, QStringLiteral("false")).toUtf8()); parsedCustoms << key; } } parsedCustoms << QStringLiteral("KADDRESSBOOK-X-IMAddress"); /* Phone numbers */ const QString phone_str = QStringLiteral("<gd:phoneNumber rel=\"%1\">%2</gd:phoneNumber>"); Q_FOREACH(const KContacts::PhoneNumber &number, contact->phoneNumbers()) { output.append(phone_str.arg(Contact::phoneTypeToScheme(number.type()), number.number()).toUtf8()); } /* Address */ Q_FOREACH(const KContacts::Address &address, contact->addresses()) { output.append("<gd:structuredPostalAddress rel='") .append(Contact::addressTypeToScheme(address.type()).toUtf8()) .append("'>"); if (!address.locality().isEmpty()) output.append("<gd:city>").append(Qt::escape(address.locality()).toUtf8()).append("</gd:city>"); if (!address.street().isEmpty()) output.append("<gd:street>").append(Qt::escape(address.street()).toUtf8()).append("</gd:street>"); if (!address.region().isEmpty()) output.append("<gd:region>").append(Qt::escape(address.region()).toUtf8()).append("</gd:region>"); if (!address.postalCode().isEmpty()) output.append("<gd:postcode>").append(Qt::escape(address.postalCode()).toUtf8()).append("</gd:postcode>"); if (!address.country().isEmpty()) output.append("<gd:country>").append(Qt::escape(address.country()).toUtf8()).append("</gd:country>"); if (!address.formattedAddress().isEmpty()) output.append("<gd:formattedAddress>").append(Qt::escape(address.formattedAddress()).toUtf8()).append("</gd:formattedAddress>"); output.append("</gd:structuredPostalAddress>"); } /* Birthday */ const QDate birthday = contact->birthday().date(); if (birthday.isValid()) { QString birthdayStr; /* We use year 1900 as a fake year for birthdays without a year specified. * Here we assume that nobody actually has a contact born in 1900 and so * we replace 1900 by "-", so that we get "--MM-dd" date, which is a valid * birthday date according to RFC6350 */ if (birthday.year() == 1900) { birthdayStr = birthday.toString(QStringLiteral("--MM-dd")); } else { birthdayStr = birthday.toString(QStringLiteral("yyyy-MM-dd")); } output.append("<gContact:birthday when='").append(birthdayStr.toUtf8()).append("'/>"); } const QStringList groups = contact->custom(QStringLiteral("GCALENDAR"), QStringLiteral("groupMembershipInfo")).split(QLatin1Char(',')); qCDebug(KGAPIDebug) << groups; if ((groups.length() > 0) && !groups.at(0).isEmpty()) { Q_FOREACH(const QString & group, groups) { bool removed = contact->groupIsDeleted(group); if (!removed) output.append(QStringLiteral("<gContact:groupMembershipInfo deleted=\"false\" href=\"%2\" />").arg(group).toUtf8()); }