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: AGPL-3.0-or-later
0005  */
0006 
0007 #include "xmlobject.h"
0008 #include "conversion/commonconversion.h"
0009 #include "conversion/kabcconversion.h"
0010 #include "conversion/kcalconversion.h"
0011 #include "conversion/kolabconversion.h"
0012 #include "kolabformatV2/event.h"
0013 #include "pimkolab_debug.h"
0014 #include "v2helpers.h"
0015 #include <QUuid>
0016 
0017 namespace Kolab
0018 {
0019 static QString createUuid()
0020 {
0021     const QString uuid = QUuid::createUuid().toString();
0022     return uuid.mid(1, uuid.size() - 2);
0023 }
0024 
0025 XMLObject::XMLObject() = default;
0026 
0027 std::string XMLObject::getSerializedUID() const
0028 {
0029     return mWrittenUID;
0030 }
0031 
0032 std::vector<std::string> XMLObject::getAttachments() const
0033 {
0034     return mAttachments;
0035 }
0036 
0037 std::string XMLObject::writeEvent(const Event &event, Version version, const std::string &productId)
0038 {
0039     mWrittenUID.clear();
0040     if (version == KolabV2) {
0041         const KCalendarCore::Event::Ptr i = Conversion::toKCalendarCore(event);
0042         if (!i) {
0043             qCCritical(PIMKOLAB_LOG) << "invalid incidence";
0044             return {};
0045         }
0046         if (i->uid().isEmpty()) {
0047             i->setUid(createUuid());
0048         }
0049         mWrittenUID = Conversion::toStdString(i->uid());
0050         // The timezone is used for created and last modified dates
0051         const QString &xml = KolabV2::Event::eventToXML(i, QStringLiteral("UTC"));
0052         return Conversion::toStdString(xml);
0053     }
0054     const std::string result = Kolab::writeEvent(event, productId);
0055     mWrittenUID = Kolab::getSerializedUID();
0056     ErrorHandler::handleLibkolabxmlErrors();
0057     return result;
0058 }
0059 
0060 Event XMLObject::readEvent(const std::string &s, Version version)
0061 {
0062     if (version == KolabV2) {
0063         QStringList attachments;
0064         const auto event = Kolab::fromXML<KCalendarCore::Event::Ptr, KolabV2::Event>(QString::fromUtf8(s.c_str()).toUtf8(), attachments);
0065         if (!event || Kolab::ErrorHandler::errorOccured()) {
0066             qCCritical(PIMKOLAB_LOG) << "failed to read xml";
0067             return {};
0068         }
0069         mAttachments.clear();
0070         mAttachments.reserve(attachments.count());
0071         for (const QString &attachment : std::as_const(attachments)) {
0072             mAttachments.push_back(Conversion::toStdString(attachment));
0073         }
0074         return Conversion::fromKCalendarCore(*event);
0075     }
0076     const Kolab::Event event = Kolab::readEvent(s, false);
0077     ErrorHandler::handleLibkolabxmlErrors();
0078     return event;
0079 }
0080 
0081 std::string XMLObject::writeTodo(const Todo &event, Version version, const std::string &productId)
0082 {
0083     mWrittenUID.clear();
0084     if (version == KolabV2) {
0085         const KCalendarCore::Todo::Ptr i = Conversion::toKCalendarCore(event);
0086         if (!i) {
0087             qCCritical(PIMKOLAB_LOG) << "invalid incidence";
0088             return {};
0089         }
0090         if (i->uid().isEmpty()) {
0091             i->setUid(createUuid());
0092         }
0093         mWrittenUID = Conversion::toStdString(i->uid());
0094         // The timezone is used for created and last modified dates
0095         const QString &xml = KolabV2::Task::taskToXML(i, QStringLiteral("UTC"));
0096         return Conversion::toStdString(xml);
0097     }
0098     const std::string result = Kolab::writeTodo(event, productId);
0099     mWrittenUID = Kolab::getSerializedUID();
0100     ErrorHandler::handleLibkolabxmlErrors();
0101     return result;
0102 }
0103 
0104 Todo XMLObject::readTodo(const std::string &s, Version version)
0105 {
0106     if (version == KolabV2) {
0107         QStringList attachments;
0108         const auto event = Kolab::fromXML<KCalendarCore::Todo::Ptr, KolabV2::Task>(QString::fromUtf8(s.c_str()).toUtf8(), attachments);
0109         if (!event || Kolab::ErrorHandler::errorOccured()) {
0110             qCCritical(PIMKOLAB_LOG) << "failed to read xml";
0111             return {};
0112         }
0113         mAttachments.clear();
0114         mAttachments.reserve(attachments.count());
0115         for (const QString &attachment : std::as_const(attachments)) {
0116             mAttachments.push_back(Conversion::toStdString(attachment));
0117         }
0118         return Conversion::fromKCalendarCore(*event);
0119     }
0120     const Kolab::Todo todo = Kolab::readTodo(s, false);
0121     ErrorHandler::handleLibkolabxmlErrors();
0122     return todo;
0123 }
0124 
0125 std::string XMLObject::writeJournal(const Journal &event, Version version, const std::string &productId)
0126 {
0127     mWrittenUID.clear();
0128     if (version == KolabV2) {
0129         const KCalendarCore::Journal::Ptr i = Conversion::toKCalendarCore(event);
0130         if (!i) {
0131             qCCritical(PIMKOLAB_LOG) << "invalid journal";
0132             return {};
0133         }
0134         if (i->uid().isEmpty()) {
0135             i->setUid(createUuid());
0136         }
0137         mWrittenUID = Conversion::toStdString(i->uid());
0138         // The timezone is used for created and last modified dates
0139         const QString &xml = KolabV2::Journal::journalToXML(i, QStringLiteral("UTC"));
0140         return Conversion::toStdString(xml);
0141     }
0142     const std::string result = Kolab::writeJournal(event, productId);
0143     mWrittenUID = Kolab::getSerializedUID();
0144     return result;
0145 }
0146 
0147 Journal XMLObject::readJournal(const std::string &s, Version version)
0148 {
0149     if (version == KolabV2) {
0150         QStringList attachments;
0151         const auto event = Kolab::fromXML<KCalendarCore::Journal::Ptr, KolabV2::Journal>(QString::fromUtf8(s.c_str()).toUtf8(), attachments);
0152         if (!event || Kolab::ErrorHandler::errorOccured()) {
0153             qCCritical(PIMKOLAB_LOG) << "failed to read xml";
0154             return {};
0155         }
0156         mAttachments.clear();
0157         mAttachments.reserve(attachments.count());
0158         for (const QString &attachment : std::as_const(attachments)) {
0159             mAttachments.push_back(Conversion::toStdString(attachment));
0160         }
0161         return Conversion::fromKCalendarCore(*event);
0162     }
0163     const Kolab::Journal journal = Kolab::readJournal(s, false);
0164     ErrorHandler::handleLibkolabxmlErrors();
0165     return journal;
0166 }
0167 
0168 std::string XMLObject::writeFreebusy(const Freebusy &event, Version version, const std::string &productId)
0169 {
0170     mWrittenUID.clear();
0171     if (version != KolabV3) {
0172         qCCritical(PIMKOLAB_LOG) << "only v3 implementation available";
0173         return {};
0174     }
0175     const std::string result = Kolab::writeFreebusy(event, productId);
0176     mWrittenUID = Kolab::getSerializedUID();
0177     return result;
0178 }
0179 
0180 Freebusy XMLObject::readFreebusy(const std::string &s, Version version)
0181 {
0182     if (version != KolabV3) {
0183         qCCritical(PIMKOLAB_LOG) << "only v3 implementation available";
0184         return {};
0185     }
0186     return Kolab::readFreebusy(s, false);
0187 }
0188 
0189 std::string XMLObject::logoAttachmentName() const
0190 {
0191     return mLogoAttachmentName;
0192 }
0193 
0194 std::string XMLObject::pictureAttachmentName() const
0195 {
0196     return mPictureAttachmentName;
0197 }
0198 
0199 std::string XMLObject::soundAttachmentName() const
0200 {
0201     return mSoundAttachmentName;
0202 }
0203 
0204 Contact XMLObject::readContact(const std::string &s, Version version)
0205 {
0206     if (version == KolabV2) {
0207         const QByteArray xmlData(s.c_str(), s.size());
0208         QString pictureAttachmentName;
0209         QString logoAttachmentName;
0210         QString soundAttachmentName;
0211         const KContacts::Addressee addressee = addresseeFromKolab(xmlData, pictureAttachmentName, logoAttachmentName, soundAttachmentName);
0212         mPictureAttachmentName = Conversion::toStdString(pictureAttachmentName);
0213         mLogoAttachmentName = Conversion::toStdString(logoAttachmentName);
0214         mSoundAttachmentName = Conversion::toStdString(soundAttachmentName);
0215         return Conversion::fromKABC(addressee);
0216     }
0217     const Kolab::Contact contact = Kolab::readContact(s, false);
0218     ErrorHandler::handleLibkolabxmlErrors();
0219     return contact;
0220 }
0221 
0222 std::string XMLObject::writeContact(const Contact &contact, Version version, const std::string &productId)
0223 {
0224     mWrittenUID.clear();
0225     if (version == KolabV2) {
0226         // FIXME attachment names are hardcoded for now
0227         KContacts::Addressee addressee = Conversion::toKABC(contact);
0228         if (addressee.uid().isEmpty()) {
0229             addressee.setUid(createUuid());
0230         }
0231         mWrittenUID = Conversion::toStdString(addressee.uid());
0232         const KolabV2::Contact contact(&addressee);
0233         return Conversion::toStdString(contact.saveXML());
0234     }
0235     const std::string result = Kolab::writeContact(contact, productId);
0236     mWrittenUID = Kolab::getSerializedUID();
0237     ErrorHandler::handleLibkolabxmlErrors();
0238     return result;
0239 }
0240 
0241 DistList XMLObject::readDistlist(const std::string &s, Version version)
0242 {
0243     if (version == KolabV2) {
0244         const QByteArray xmlData(s.c_str(), s.size());
0245         const KContacts::ContactGroup contactGroup = contactGroupFromKolab(xmlData);
0246         return Conversion::fromKABC(contactGroup);
0247     }
0248     const Kolab::DistList distlist = Kolab::readDistlist(s, false);
0249     ErrorHandler::handleLibkolabxmlErrors();
0250     return distlist;
0251 }
0252 
0253 std::string XMLObject::writeDistlist(const DistList &distlist, Version version, const std::string &productId)
0254 {
0255     mWrittenUID.clear();
0256     if (version == KolabV2) {
0257         KContacts::ContactGroup contactGroup = Conversion::toKABC(distlist);
0258         if (contactGroup.id().isEmpty()) {
0259             contactGroup.setId(createUuid());
0260         }
0261         mWrittenUID = Conversion::toStdString(contactGroup.id());
0262         const KolabV2::DistributionList d(&contactGroup);
0263         return Conversion::toStdString(d.saveXML());
0264     }
0265     const std::string result = Kolab::writeDistlist(distlist, productId);
0266     mWrittenUID = Kolab::getSerializedUID();
0267     ErrorHandler::handleLibkolabxmlErrors();
0268     return result;
0269 }
0270 
0271 Note XMLObject::readNote(const std::string &s, Version version)
0272 {
0273     if (version == KolabV2) {
0274         const KMime::Message::Ptr msg = noteFromKolab(QByteArray(s.c_str(), s.length()), QDateTime());
0275         if (!msg || Kolab::ErrorHandler::errorOccured()) {
0276             qCCritical(PIMKOLAB_LOG) << "failed to read xml";
0277             return {};
0278         }
0279         return Conversion::fromNote(msg);
0280     }
0281     const Kolab::Note note = Kolab::readNote(s, false);
0282     ErrorHandler::handleLibkolabxmlErrors();
0283     return note;
0284 }
0285 
0286 std::string XMLObject::writeNote(const Note &note, Version version, const std::string &productId)
0287 {
0288     mWrittenUID.clear();
0289     if (version == KolabV2) {
0290         Note noteWithUID = note;
0291         if (noteWithUID.uid().empty()) {
0292             noteWithUID.setUid(Conversion::toStdString(createUuid()));
0293         }
0294         mWrittenUID = noteWithUID.uid();
0295         const KMime::Message::Ptr n = Conversion::toNote(noteWithUID);
0296         const QByteArray &xml = noteToKolabXML(n);
0297         return std::string(xml.constData());
0298     }
0299     const std::string result = Kolab::writeNote(note, productId);
0300     mWrittenUID = Kolab::getSerializedUID();
0301     ErrorHandler::handleLibkolabxmlErrors();
0302     return result;
0303 }
0304 
0305 Configuration XMLObject::readConfiguration(const std::string &s, Version version)
0306 {
0307     if (version == KolabV2) {
0308         QString lang;
0309         const QStringList dict = readLegacyDictionaryConfiguration(QByteArray(s.c_str(), s.length()), lang);
0310         if (lang.isEmpty()) {
0311             qCCritical(PIMKOLAB_LOG) << "not a dictionary or not a v2 configuration object";
0312             return {};
0313         }
0314         std::vector<std::string> entries;
0315         entries.reserve(dict.size());
0316         for (const QString &e : std::as_const(dict)) {
0317             entries.push_back(Conversion::toStdString(e));
0318         }
0319         Kolab::Dictionary dictionary(Conversion::toStdString(lang));
0320         dictionary.setEntries(entries);
0321         return Configuration(dictionary);
0322     }
0323     const Kolab::Configuration configuration = Kolab::readConfiguration(s, false);
0324     ErrorHandler::handleLibkolabxmlErrors();
0325     return configuration;
0326 }
0327 
0328 std::string XMLObject::writeConfiguration(const Configuration &configuration, Version version, const std::string &productId)
0329 {
0330     mWrittenUID.clear();
0331     if (version != KolabV3) {
0332         qCCritical(PIMKOLAB_LOG) << "only v3 implementation available";
0333         return {};
0334     }
0335     const std::string result = Kolab::writeConfiguration(configuration, productId);
0336     mWrittenUID = Kolab::getSerializedUID();
0337     ErrorHandler::handleLibkolabxmlErrors();
0338     return result;
0339 }
0340 
0341 File XMLObject::readFile(const std::string &s, Version version)
0342 {
0343     if (version == KolabV2) {
0344         qCCritical(PIMKOLAB_LOG) << "only v3 implementation available";
0345         return {};
0346     }
0347     const Kolab::File file = Kolab::readFile(s, false);
0348     ErrorHandler::handleLibkolabxmlErrors();
0349     return file;
0350 }
0351 
0352 std::string XMLObject::writeFile(const File &file, Version version, const std::string &productId)
0353 {
0354     mWrittenUID.clear();
0355     if (version != KolabV3) {
0356         qCCritical(PIMKOLAB_LOG) << "only v3 implementation available";
0357         return {};
0358     }
0359     const std::string result = Kolab::writeFile(file, productId);
0360     mWrittenUID = Kolab::getSerializedUID();
0361     ErrorHandler::handleLibkolabxmlErrors();
0362     return result;
0363 }
0364 }