File indexing completed on 2024-11-24 04:44:14

0001 /*
0002  * SPDX-FileCopyrightText: 2012 Christian Mollekopf <mollekopf@kolabsys.com>
0003  *
0004  * SPDX-License-Identifier: LGPL-3.0-or-later
0005  */
0006 
0007 #include "v2helpers.h"
0008 
0009 #include "pimkolab_debug.h"
0010 
0011 #include <QBuffer>
0012 
0013 namespace Kolab
0014 {
0015 void getAttachments(KCalendarCore::Incidence::Ptr incidence, const QStringList &attachments, const KMime::Message::Ptr &mimeData)
0016 {
0017     if (!incidence) {
0018         qCCritical(PIMKOLAB_LOG) << "Invalid incidence";
0019         return;
0020     }
0021     for (const QString &name : attachments) {
0022         QByteArray type;
0023         KMime::Content *content = Mime::findContentByName(mimeData, name, type);
0024         if (!content) { // guard against malformed events with non-existent attachments
0025             qCWarning(PIMKOLAB_LOG) << "could not find attachment: " << name.toUtf8() << type;
0026             continue;
0027         }
0028         const QByteArray c = content->decodedContent().toBase64();
0029         KCalendarCore::Attachment attachment(c, QString::fromLatin1(type));
0030         attachment.setLabel(name);
0031         incidence->addAttachment(attachment);
0032         qCDebug(PIMKOLAB_LOG) << "ATTACHMENT NAME" << name << type;
0033     }
0034 }
0035 
0036 static QImage getPicture(const QString &pictureAttachmentName, const KMime::Message::Ptr &data, QByteArray &type)
0037 {
0038     if (!data) {
0039         qCCritical(PIMKOLAB_LOG) << "empty message";
0040         return {};
0041     }
0042     KMime::Content *imgContent = Mime::findContentByName(data, pictureAttachmentName /*"kolab-picture.png"*/, type);
0043     if (!imgContent) {
0044         qCWarning(PIMKOLAB_LOG) << "could not find picture: " << pictureAttachmentName;
0045         return {};
0046     }
0047     QByteArray imgData = imgContent->decodedContent();
0048     QBuffer buffer(&imgData);
0049     buffer.open(QIODevice::ReadOnly);
0050     QImage image;
0051     bool success = false;
0052     if (type == "image/jpeg") {
0053         success = image.load(&buffer, "JPEG");
0054         // FIXME I tried getting the code to interpret the picture as PNG, but the VCard implementation writes it as JPEG anyways...
0055         //         if (success) {
0056         //             QByteArray pic;
0057         //             QBuffer b(&pic);
0058         //             b.open(QIODevice::ReadWrite);
0059         //             Q_ASSERT(image.save(&b, "PNG"));
0060         //             b.close();
0061         //             Debug() << pic.toBase64();
0062         //             QBuffer b2(&pic);
0063         //             b2.open(QIODevice::ReadOnly);
0064         //             success = image.load(&b2, "PNG");
0065         //             b2.close();
0066         //             Q_ASSERT(success);
0067         //         }
0068     } else {
0069         type = "image/png";
0070         success = image.load(&buffer, "PNG");
0071     }
0072     buffer.close();
0073     if (!success) {
0074         qCWarning(PIMKOLAB_LOG) << "failed to load picture";
0075     }
0076     return image;
0077 }
0078 
0079 KContacts::Addressee addresseeFromKolab(const QByteArray &xmlData, const KMime::Message::Ptr &data)
0080 {
0081     if (!data) {
0082         qCCritical(PIMKOLAB_LOG) << "empty message";
0083         return {};
0084     }
0085     KContacts::Addressee addressee;
0086     //     qCDebug(PIMKOLAB_LOG) << "xmlData " << xmlData;
0087     KolabV2::Contact contact(QString::fromUtf8(xmlData));
0088     QByteArray type;
0089     const QString &pictureAttachmentName = contact.pictureAttachmentName();
0090     if (!pictureAttachmentName.isEmpty()) {
0091         const QImage &img = getPicture(pictureAttachmentName, data, type);
0092         contact.setPicture(img, QString::fromLatin1(type));
0093     }
0094 
0095     const QString &logoAttachmentName = contact.logoAttachmentName();
0096     if (!logoAttachmentName.isEmpty()) {
0097         contact.setLogo(getPicture(logoAttachmentName, data, type), QString::fromLatin1(type));
0098     }
0099 
0100     const QString &soundAttachmentName = contact.soundAttachmentName();
0101     if (!soundAttachmentName.isEmpty()) {
0102         KMime::Content *content = Mime::findContentByName(data, soundAttachmentName /*"sound"*/, type);
0103         if (content) {
0104             const QByteArray &sData = content->decodedContent();
0105             contact.setSound(sData);
0106         } else {
0107             qCWarning(PIMKOLAB_LOG) << "could not find sound: " << soundAttachmentName;
0108         }
0109     }
0110     contact.saveTo(&addressee);
0111     return addressee;
0112 }
0113 
0114 KContacts::Addressee addresseeFromKolab(const QByteArray &xmlData, QString &pictureAttachmentName, QString &logoAttachmentName, QString &soundAttachmentName)
0115 {
0116     KContacts::Addressee addressee;
0117     KolabV2::Contact contact(QString::fromUtf8(xmlData));
0118     pictureAttachmentName = contact.pictureAttachmentName();
0119     logoAttachmentName = contact.logoAttachmentName();
0120     soundAttachmentName = contact.soundAttachmentName();
0121     contact.saveTo(&addressee);
0122     return addressee;
0123 }
0124 
0125 static QByteArray createPicture(const QImage &img, const QString & /*format*/, QByteArray &type)
0126 {
0127     QByteArray pic;
0128     QBuffer buffer(&pic);
0129     buffer.open(QIODevice::WriteOnly);
0130     type = "image/png";
0131     // FIXME it's not possible to save jpegs lossless, so we always use png. otherwise we would compress the image on every write.
0132     //     if (format == "image/jpeg") {
0133     //         type = "image/jpeg";
0134     //         img.save(&buffer, "JPEG");
0135     //     } else {
0136     img.save(&buffer, "PNG");
0137     //     }
0138     buffer.close();
0139     return pic;
0140 }
0141 
0142 KMime::Message::Ptr contactToKolabFormat(const KolabV2::Contact &contact, const QString &productId)
0143 {
0144     KMime::Message::Ptr message = Mime::createMessage(QByteArray(KOLAB_TYPE_CONTACT), false, productId.toLatin1());
0145     if (!message) {
0146         qCCritical(PIMKOLAB_LOG) << "empty message";
0147         return {};
0148     }
0149     message->subject()->fromUnicodeString(contact.uid(), "utf-8");
0150     message->from()->fromUnicodeString(contact.fullEmail(), "utf-8");
0151 
0152     KMime::Content *content = Mime::createMainPart(KOLAB_TYPE_CONTACT, contact.saveXML().toUtf8());
0153     message->appendContent(content);
0154 
0155     if (!contact.picture().isNull()) {
0156         QByteArray type;
0157         const QByteArray &pic = createPicture(contact.picture(), contact.pictureFormat(), type);
0158         content = Mime::createAttachmentPart(QByteArray(), type, /*"kolab-picture.png"*/ contact.pictureAttachmentName(), pic);
0159         message->appendContent(content);
0160     }
0161 
0162     if (!contact.logo().isNull()) {
0163         QByteArray type;
0164         const QByteArray &pic = createPicture(contact.logo(), contact.logoFormat(), type);
0165         content = Mime::createAttachmentPart(QByteArray(), type, /*"kolab-logo.png"*/ contact.logoAttachmentName(), pic);
0166         message->appendContent(content);
0167     }
0168 
0169     if (!contact.sound().isEmpty()) {
0170         content = Mime::createAttachmentPart(QByteArray(), "audio/unknown", /*"sound"*/ contact.soundAttachmentName(), contact.sound());
0171         message->appendContent(content);
0172     }
0173 
0174     message->assemble();
0175     return message;
0176 }
0177 
0178 KContacts::ContactGroup contactGroupFromKolab(const QByteArray &xmlData)
0179 {
0180     KContacts::ContactGroup contactGroup;
0181     //     qCDebug(PIMKOLAB_LOG) << "xmlData " << xmlData;
0182     KolabV2::DistributionList distList(QString::fromUtf8(xmlData));
0183     distList.saveTo(&contactGroup);
0184     return contactGroup;
0185 }
0186 
0187 KMime::Message::Ptr distListToKolabFormat(const KolabV2::DistributionList &distList, const QString &productId)
0188 {
0189     KMime::Message::Ptr message = Mime::createMessage(KOLAB_TYPE_DISTLIST_V2, false, productId.toLatin1());
0190     if (!message) {
0191         qCCritical(PIMKOLAB_LOG) << "empty message";
0192         return {};
0193     }
0194     message->subject()->fromUnicodeString(distList.uid(), "utf-8");
0195     message->from()->fromUnicodeString(distList.uid(), "utf-8");
0196 
0197     KMime::Content *content = Mime::createMainPart(KOLAB_TYPE_DISTLIST_V2, distList.saveXML().toUtf8());
0198     message->appendContent(content);
0199 
0200     message->assemble();
0201     return message;
0202 }
0203 
0204 KMime::Message::Ptr noteFromKolab(const QByteArray &xmlData, const QDateTime &creationDate)
0205 {
0206     KolabV2::Note j;
0207     if (!j.load(QString::fromUtf8(xmlData))) {
0208         qCWarning(PIMKOLAB_LOG) << "failed to read note";
0209         return {};
0210     }
0211 
0212     Akonadi::NoteUtils::NoteMessageWrapper note;
0213     note.setTitle(j.summary());
0214     note.setText(j.body());
0215     note.setFrom(QStringLiteral("kolab@kde4"));
0216     note.setCreationDate(creationDate);
0217     return note.message();
0218 }
0219 
0220 KMime::Message::Ptr noteToKolab(const KMime::Message::Ptr &msg, const QString &productId)
0221 {
0222     if (!msg) {
0223         qCCritical(PIMKOLAB_LOG) << "empty message";
0224         return {};
0225     }
0226     Akonadi::NoteUtils::NoteMessageWrapper note(msg);
0227     return Mime::createMessage(note.title(), QStringLiteral(KOLAB_TYPE_NOTE), QStringLiteral(KOLAB_TYPE_NOTE), noteToKolabXML(msg), false, productId);
0228 }
0229 
0230 QByteArray noteToKolabXML(const KMime::Message::Ptr &msg)
0231 {
0232     if (!msg) {
0233         qCCritical(PIMKOLAB_LOG) << "empty message";
0234         return {};
0235     }
0236     Akonadi::NoteUtils::NoteMessageWrapper note(msg);
0237     KolabV2::Note j;
0238     j.setSummary(note.title());
0239     j.setBody(note.text());
0240     return j.saveXML().toUtf8();
0241 }
0242 
0243 QStringList readLegacyDictionaryConfiguration(const QByteArray &xmlData, QString &language)
0244 {
0245     QStringList dictionary;
0246     const QDomDocument xmlDoc = KolabV2::KolabBase::loadDocument(QString::fromUtf8(xmlData)); // TODO extract function from V2 format
0247     if (xmlDoc.isNull()) {
0248         qCCritical(PIMKOLAB_LOG) << "Failed to read the xml document";
0249         return {};
0250     }
0251 
0252     QDomElement top = xmlDoc.documentElement();
0253 
0254     if (top.tagName() != QLatin1StringView("configuration")) {
0255         qCWarning(PIMKOLAB_LOG) << QStringLiteral("XML error: Top tag was %1 instead of the expected configuration").arg(top.tagName());
0256         return {};
0257     }
0258 
0259     for (QDomNode n = top.firstChild(); !n.isNull(); n = n.nextSibling()) {
0260         if (n.isComment() || !n.isElement()) {
0261             continue;
0262         }
0263         const QDomElement e = n.toElement();
0264         const QString tagName = e.tagName();
0265         if (tagName == QLatin1StringView("language")) {
0266             language = e.text();
0267         } else if (tagName == QLatin1Char('e')) {
0268             dictionary.append(e.text());
0269         }
0270     }
0271     return dictionary;
0272 }
0273 }