diff --git a/resources/kolab/pimkolab/kolabformat/mimeobject.cpp b/resources/kolab/pimkolab/kolabformat/mimeobject.cpp index 3e6e61c61..9a6cda1cf 100644 --- a/resources/kolab/pimkolab/kolabformat/mimeobject.cpp +++ b/resources/kolab/pimkolab/kolabformat/mimeobject.cpp @@ -1,820 +1,820 @@ /* * Copyright (C) 2012 Sofia Balicka * Copyright (C) 2014 Christian Mollekopf * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program. If not, see . */ #include "mimeobject.h" #include "conversion/kcalconversion.h" #include "conversion/kolabconversion.h" #include "conversion/kabcconversion.h" #include "conversion/commonconversion.h" #include "kolabformat/kolabobject.h" #include "kolabformat/xmlobject.h" #include "kolabformat/v2helpers.h" #include "mime/mimeutils.h" #include "libkolab-version.h" #include #include #include #include "pimkolab_debug.h" Q_DECLARE_METATYPE(Kolab::Event) Q_DECLARE_METATYPE(Kolab::Todo) Q_DECLARE_METATYPE(Kolab::Journal) Q_DECLARE_METATYPE(Kolab::Contact) Q_DECLARE_METATYPE(Kolab::DistList) Q_DECLARE_METATYPE(Kolab::Note) Q_DECLARE_METATYPE(Kolab::Freebusy) Q_DECLARE_METATYPE(Kolab::Configuration) static inline std::string eventKolabType() { return std::string(KOLAB_TYPE_EVENT); } static inline std::string todoKolabType() { return std::string(KOLAB_TYPE_TASK); } static inline std::string journalKolabType() { return std::string(KOLAB_TYPE_JOURNAL); } static inline std::string contactKolabType() { return std::string(KOLAB_TYPE_CONTACT); } static inline std::string distlistKolabType() { return std::string(KOLAB_TYPE_DISTLIST); } static inline std::string distlistKolabTypeCompat() { return std::string(KOLAB_TYPE_DISTLIST_V2); } static inline std::string noteKolabType() { return std::string(KOLAB_TYPE_NOTE); } static inline std::string configurationKolabType() { return std::string(KOLAB_TYPE_CONFIGURATION); } static inline std::string dictKolabType() { return std::string(KOLAB_TYPE_DICT); } static inline std::string freebusyKolabType() { return std::string(KOLAB_TYPE_FREEBUSY); } static inline std::string relationKolabType() { return std::string(KOLAB_TYPE_RELATION); } static inline std::string xCalMimeType() { return std::string(MIME_TYPE_XCAL); } static inline std::string xCardMimeType() { return std::string(MIME_TYPE_XCARD); } static inline std::string kolabMimeType() { return std::string(MIME_TYPE_KOLAB); } static std::string getProductId(const std::string &pId) { if (pId.empty()) { return LIBKOLAB_LIB_VERSION_STRING; } return pId + ' ' + LIBKOLAB_LIB_VERSION_STRING; } namespace Kolab { static Kolab::ObjectType getObjectType(const std::string &type) { if (type == eventKolabType()) { return EventObject; } else if (type == todoKolabType()) { return TodoObject; } else if (type == journalKolabType()) { return JournalObject; } else if (type == contactKolabType()) { return ContactObject; } else if (type == distlistKolabType() || type == distlistKolabTypeCompat()) { return DistlistObject; } else if (type == noteKolabType()) { return NoteObject; } else if (type == freebusyKolabType()) { return FreebusyObject; } else if (boost::contains(type, dictKolabType())) { //Previous versions appended the language to the type return DictionaryConfigurationObject; } else if (type == relationKolabType()) { return RelationConfigurationObject; } qCWarning(PIMKOLAB_LOG) <<"Unknown object type: " << type; return Kolab::InvalidObject; } static QByteArray getTypeString(Kolab::ObjectType type) { switch (type) { case EventObject: return KOLAB_TYPE_EVENT; case TodoObject: return KOLAB_TYPE_TASK; case JournalObject: return KOLAB_TYPE_JOURNAL; case FreebusyObject: return KOLAB_TYPE_FREEBUSY; case ContactObject: return KOLAB_TYPE_CONTACT; case DistlistObject: return KOLAB_TYPE_DISTLIST; case NoteObject: return KOLAB_TYPE_NOTE; case DictionaryConfigurationObject: return KOLAB_TYPE_CONFIGURATION; case RelationConfigurationObject: return KOLAB_TYPE_RELATION; default: qCCritical(PIMKOLAB_LOG) << "unknown type "<< type; } return QByteArray(); } static QByteArray getMimeType(Kolab::ObjectType type) { switch (type) { case EventObject: case TodoObject: case JournalObject: case FreebusyObject: return MIME_TYPE_XCAL; case ContactObject: case DistlistObject: return MIME_TYPE_XCARD; case NoteObject: case DictionaryConfigurationObject: case RelationConfigurationObject: return MIME_TYPE_KOLAB; default: qCCritical(PIMKOLAB_LOG) << "unknown type "<< type; } return QByteArray(); } static Kolab::ObjectType detectType(const KMime::Message::Ptr &msg) { Q_FOREACH (const QByteArray &type, Mime::getContentMimeTypeList(msg)) { Kolab::ObjectType t = getObjectType(type.toStdString()); //works for v2 types if (t != InvalidObject) { return t; } } return InvalidObject; } static void printMessageDebugInfo(const KMime::Message::Ptr &msg) { //TODO replace by Debug stream for Mimemessage qCDebug(PIMKOLAB_LOG) << "MessageId: " << msg->messageID()->asUnicodeString(); qCDebug(PIMKOLAB_LOG) << "Subject: " << msg->subject()->asUnicodeString(); // Debug() << msg->encodedContent(); } //@cond PRIVATE class MIMEObject::Private { public: Private() { } QVariant readKolabV2(const KMime::Message::Ptr &msg, Kolab::ObjectType objectType); QVariant readKolabV3(const KMime::Message::Ptr &msg, Kolab::ObjectType objectType); QVariant parseMimeMessage(const KMime::Message::Ptr &msg); QVariant parseMimeMessage(const std::string &s); ObjectType mObjectType = InvalidObject; Version mVersion = KolabV3; ObjectType mOverrideObjectType = InvalidObject; Version mOverrideVersion = KolabV3; bool mDoOverrideVersion = false; QVariant mObject; }; //@endcond static std::vector getAttachments(const std::vector &attachments, const KMime::Message::Ptr &msg) { std::vector allAttachments; foreach (const Kolab::Attachment &attachment, attachments) { if (!attachment.uri().empty()) { const Kolab::Attachment extracted = Mime::getAttachment(attachment.uri(), msg); if (extracted.isValid()) { allAttachments.push_back(extracted); } } else { allAttachments.push_back(attachment); } } return allAttachments; } static std::vector getAttachments(const QStringList &attachmentNames, const KMime::Message::Ptr &msg) { std::vector allAttachments; foreach (const QString &name, attachmentNames) { const Kolab::Attachment extracted = Mime::getAttachmentByName(name, msg); if (extracted.isValid()) { allAttachments.push_back(extracted); } } return allAttachments; } QVariant MIMEObject::Private::readKolabV2(const KMime::Message::Ptr &msg, Kolab::ObjectType objectType) { if (objectType == DictionaryConfigurationObject) { KMime::Content *xmlContent = Mime::findContentByType(msg, "application/xml"); if (!xmlContent) { qCCritical(PIMKOLAB_LOG) << "no application/xml part found"; printMessageDebugInfo(msg); return InvalidObject; } const QByteArray &xmlData = xmlContent->decodedContent(); QString dictionaryLanguage; const QStringList entries = Kolab::readLegacyDictionaryConfiguration(xmlData, dictionaryLanguage); mObjectType = objectType; Kolab::Dictionary dictionary(Conversion::toStdString(dictionaryLanguage)); std::vector convertedEntries; convertedEntries.reserve(entries.count()); foreach (const QString &value, entries) { convertedEntries.push_back(Conversion::toStdString(value)); } dictionary.setEntries(convertedEntries); return QVariant::fromValue(Kolab::Configuration(dictionary)); } KMime::Content *xmlContent = Mime::findContentByType(msg, getTypeString(objectType)); if (!xmlContent) { qCCritical(PIMKOLAB_LOG) << "no part with type" << getTypeString(objectType) << " found"; printMessageDebugInfo(msg); return QVariant(); } const QByteArray &xmlData = xmlContent->decodedContent(); if (xmlData.isEmpty()) { qCCritical(PIMKOLAB_LOG) << "no content in message part with type" << getTypeString(objectType); printMessageDebugInfo(msg); return QVariant(); } QVariant variant; switch (objectType) { case EventObject: { QStringList attachments; KCalCore::Event::Ptr kEvent = fromXML(xmlData, attachments); if (kEvent) { Kolab::Event event = Kolab::Conversion::fromKCalCore(*kEvent); event.setAttachments(getAttachments(attachments, msg)); variant = QVariant::fromValue(event); } break; } case TodoObject: { QStringList attachments; KCalCore::Todo::Ptr kTodo = fromXML(xmlData, attachments); if (kTodo) { Kolab::Todo todo = Kolab::Conversion::fromKCalCore(*kTodo); todo.setAttachments(getAttachments(attachments, msg)); variant = QVariant::fromValue(todo); } break; } case JournalObject: { QStringList attachments; KCalCore::Journal::Ptr kJournal = fromXML(xmlData, attachments); if (kJournal) { Kolab::Journal journal = Kolab::Conversion::fromKCalCore(*kJournal); journal.setAttachments(getAttachments(attachments, msg)); variant = QVariant::fromValue(journal); } break; } case ContactObject: { KContacts::Addressee kContact = addresseeFromKolab(xmlData, msg); Kolab::Contact contact = Kolab::Conversion::fromKABC(kContact); variant = QVariant::fromValue(contact); break; } case DistlistObject: { KContacts::ContactGroup kContactGroup = contactGroupFromKolab(xmlData); Kolab::DistList distlist = Kolab::Conversion::fromKABC(kContactGroup); variant = QVariant::fromValue(distlist); break; } case NoteObject: { - KMime::Message::Ptr kNote = noteFromKolab(xmlData, KDateTime(msg->date()->dateTime())); + KMime::Message::Ptr kNote = noteFromKolab(xmlData, msg->date()->dateTime()); Kolab::Note note = Kolab::Conversion::fromNote(kNote); variant = QVariant::fromValue(note); break; } default: CRITICAL(QStringLiteral("no kolab object found ")); break; } if (ErrorHandler::errorOccured()) { printMessageDebugInfo(msg); return QVariant(); } mObjectType = objectType; return variant; } QVariant MIMEObject::Private::readKolabV3(const KMime::Message::Ptr &msg, Kolab::ObjectType objectType) { KMime::Content *const xmlContent = Mime::findContentByType(msg, getMimeType(objectType)); if (!xmlContent) { qCCritical(PIMKOLAB_LOG) << "no " << getMimeType(objectType) << " part found"; printMessageDebugInfo(msg); return InvalidObject; } const QByteArray &content = xmlContent->decodedContent(); const std::string xml = std::string(content.data(), content.size()); QVariant variant; switch (objectType) { case EventObject: { Kolab::Event event = Kolab::readEvent(xml, false); event.setAttachments(getAttachments(event.attachments(), msg)); variant = QVariant::fromValue(event); break; } case TodoObject: { Kolab::Todo todo = Kolab::readTodo(xml, false); todo.setAttachments(getAttachments(todo.attachments(), msg)); variant = QVariant::fromValue(todo); break; } case JournalObject: { Kolab::Journal journal = Kolab::readJournal(xml, false); journal.setAttachments(getAttachments(journal.attachments(), msg)); variant = QVariant::fromValue(journal); break; } case ContactObject: variant = QVariant::fromValue(Kolab::readContact(xml, false)); break; case DistlistObject: variant = QVariant::fromValue(Kolab::readDistlist(xml, false)); break; case NoteObject: variant = QVariant::fromValue(Kolab::readNote(xml, false)); break; case FreebusyObject: variant = QVariant::fromValue(Kolab::readFreebusy(xml, false)); break; case DictionaryConfigurationObject: case RelationConfigurationObject: variant = QVariant::fromValue(Kolab::readConfiguration(xml, false)); break; default: qCCritical(PIMKOLAB_LOG) << "no kolab object found "; printMessageDebugInfo(msg); break; } if (ErrorHandler::errorOccured()) { printMessageDebugInfo(msg); return QVariant(); } mObjectType = objectType; return variant; } QVariant MIMEObject::Private::parseMimeMessage(const KMime::Message::Ptr &msg) { ErrorHandler::clearErrors(); mObjectType = InvalidObject; if (msg->contents().isEmpty()) { qCCritical(PIMKOLAB_LOG) << "message has no contents (we likely failed to parse it correctly)"; printMessageDebugInfo(msg); return QVariant(); } Kolab::ObjectType objectType = InvalidObject; if (mOverrideObjectType == InvalidObject) { if (KMime::Headers::Base *xKolabHeader = msg->headerByType(X_KOLAB_TYPE_HEADER)) { objectType = getObjectType(xKolabHeader->asUnicodeString().trimmed().toStdString()); } else { qCWarning(PIMKOLAB_LOG) <<"could not find the X-Kolab-Type Header, trying autodetection"; //This works only for v2 messages atm. objectType = detectType(msg); } } else { objectType = mOverrideObjectType; } if (objectType == InvalidObject) { qCCritical(PIMKOLAB_LOG) << "unable to detect object type"; printMessageDebugInfo(msg); return QVariant(); } if (!mDoOverrideVersion) { KMime::Headers::Base *xKolabVersion = msg->headerByType(X_KOLAB_MIME_VERSION_HEADER); if (!xKolabVersion) { //For backwards compatibility to development versions, can be removed in future versions xKolabVersion = msg->headerByType(X_KOLAB_MIME_VERSION_HEADER_COMPAT); } if (!xKolabVersion || xKolabVersion->asUnicodeString() == KOLAB_VERSION_V2) { mVersion = KolabV2; } else { if (xKolabVersion->asUnicodeString() != KOLAB_VERSION_V3) { //TODO version compatibility check? qCWarning(PIMKOLAB_LOG) <<"Kolab Version Header available but not on the same version as the implementation: " << xKolabVersion->asUnicodeString(); } mVersion = KolabV3; } } else { mVersion = mOverrideVersion; } if (mVersion == KolabV2) { return readKolabV2(msg, objectType); } return readKolabV3(msg, objectType); } QVariant MIMEObject::Private::parseMimeMessage(const std::string &s) { KMime::Message::Ptr msg(new KMime::Message); msg->setContent(QByteArray(s.c_str())); msg->parse(); return parseMimeMessage(msg); } MIMEObject::MIMEObject() : d(new MIMEObject::Private) { } MIMEObject::~MIMEObject() { delete d; } void MIMEObject::setObjectType(ObjectType type) { d->mOverrideObjectType = type; } void MIMEObject::setVersion(Version version) { d->mOverrideVersion = version; d->mDoOverrideVersion = true; } static std::string createCid() { return QStringLiteral("cid:%1@%2").arg(KRandom::randomString(16), QStringLiteral("kolab.resource.akonadi")).toStdString(); } std::vector convertToReferences(const std::vector &attachments, std::vector &attachmentCids) { std::vector attachmentsWithReferences; Q_FOREACH (const Kolab::Attachment &a, attachments) { Kolab::Attachment attachment; attachment.setLabel(a.label()); const std::string cid = a.uri().empty() ? createCid() : a.uri(); attachmentCids.push_back(cid); attachment.setUri(cid, a.mimetype()); //Serialize the attachment as attachment with uri, referencing the created mime-part attachmentsWithReferences.push_back(attachment); } return attachmentsWithReferences; } template static T convertAttachmentsToReferences(const T &incidence, std::vector &attachmentCids) { T removedAttachments = incidence; removedAttachments.setAttachments(convertToReferences(incidence.attachments(), attachmentCids)); return removedAttachments; } static void addAttachments(KMime::Message::Ptr msg, const std::vector &attachments, std::vector &attachmentCids) { int index = 0; foreach (const Attachment &attachment, attachments) { const std::string data = attachment.data(); const std::string cid = attachmentCids.empty() ? attachment.uri() : attachmentCids.at(index); msg->addContent(Mime::createAttachmentPart(Mime::fromCid(QString::fromStdString(cid.c_str())).toLatin1(), QByteArray(attachment.mimetype().c_str()), QString::fromStdString(attachment.label()), QByteArray(data.c_str(), data.size()))); index++; } } ObjectType MIMEObject::parseMessage(const std::string &msg) { d->mObject = d->parseMimeMessage(msg); return d->mObjectType; } ObjectType MIMEObject::getType() const { return d->mObjectType; } Version MIMEObject::getVersion() const { return d->mVersion; } Kolab::Event MIMEObject::getEvent() const { return d->mObject.value(); } Kolab::Todo MIMEObject::getTodo() const { return d->mObject.value(); } Kolab::Journal MIMEObject::getJournal() const { return d->mObject.value(); } Kolab::Note MIMEObject::getNote() const { return d->mObject.value(); } Kolab::Contact MIMEObject::getContact() const { return d->mObject.value(); } Kolab::DistList MIMEObject::getDistlist() const { return d->mObject.value(); } Kolab::Freebusy MIMEObject::getFreebusy() const { return d->mObject.value(); } Kolab::Configuration MIMEObject::getConfiguration() const { return d->mObject.value(); } std::string MIMEObject::writeEvent(const Event &event, Version version, const std::string &pId) { ErrorHandler::clearErrors(); const std::string productId = getProductId(pId); KMime::Message::Ptr msg; Kolab::XMLObject xmlObject; std::vector attachmentCids; if (version == KolabV3) { const std::string xml = xmlObject.writeEvent(convertAttachmentsToReferences(event, attachmentCids), version, productId); msg = Mime::createMessage(xCalMimeType(), eventKolabType(), xml, true, productId, event.organizer().email(), event.organizer().name(), event.uid()); } else if (version == KolabV2) { const std::string xml = xmlObject.writeEvent(event, version, productId); msg = Mime::createMessage(eventKolabType(), eventKolabType(), xml, false, productId, event.organizer().email(), event.organizer().name(), event.uid()); } addAttachments(msg, event.attachments(), attachmentCids); msg->assemble(); return msg->encodedContent().data(); } Event MIMEObject::readEvent(const std::string &s) { return d->parseMimeMessage(s).value(); } std::string MIMEObject::writeTodo(const Todo &todo, Version version, const std::string &pId) { ErrorHandler::clearErrors(); const std::string productId = getProductId(pId); KMime::Message::Ptr msg; Kolab::XMLObject xmlObject; std::vector attachmentCids; if (version == KolabV3) { const std::string xml = xmlObject.writeTodo(convertAttachmentsToReferences(todo, attachmentCids), version, productId); msg = Mime::createMessage(xCalMimeType(), todoKolabType(), xml, true, productId, todo.organizer().email(), todo.organizer().name(), todo.uid()); } else if (version == KolabV2) { const std::string xml = xmlObject.writeTodo(todo, version, productId); msg = Mime::createMessage(todoKolabType(), todoKolabType(), xml, false, productId, todo.organizer().email(), todo.organizer().name(), todo.uid()); } addAttachments(msg, todo.attachments(), attachmentCids); msg->assemble(); return msg->encodedContent().data(); } Todo MIMEObject::readTodo(const std::string &s) { return d->parseMimeMessage(s).value(); } std::string MIMEObject::writeJournal(const Journal &journal, Version version, const std::string &pId) { ErrorHandler::clearErrors(); const std::string productId = getProductId(pId); KMime::Message::Ptr msg; Kolab::XMLObject xmlObject; std::vector attachmentCids; if (version == KolabV3) { const std::string xml = xmlObject.writeJournal(convertAttachmentsToReferences(journal, attachmentCids), version, productId); msg = Mime::createMessage(xCalMimeType(), journalKolabType(), xml, true, productId, std::string(), std::string(), journal.uid()); } else if (version == KolabV2) { const std::string xml = xmlObject.writeJournal(journal, version, productId); msg = Mime::createMessage(journalKolabType(), journalKolabType(), xml, false, productId, std::string(), std::string(), journal.uid()); } addAttachments(msg, journal.attachments(), attachmentCids); msg->assemble(); return msg->encodedContent().data(); } Journal MIMEObject::readJournal(const std::string &s) { return d->parseMimeMessage(s).value(); } std::string MIMEObject::writeNote(const Note ¬e, Version version, const std::string &pId) { ErrorHandler::clearErrors(); const std::string productId = getProductId(pId); KMime::Message::Ptr msg; Kolab::XMLObject xmlObject; std::vector attachmentCids; if (version == KolabV3) { const std::string xml = xmlObject.writeNote(convertAttachmentsToReferences(note, attachmentCids), version, productId); msg = Mime::createMessage(kolabMimeType(), noteKolabType(), xml, true, productId, std::string(), std::string(), note.uid()); } else if (version == KolabV2) { const std::string xml = xmlObject.writeNote(note, version, productId); msg = Mime::createMessage(noteKolabType(), noteKolabType(), xml, false, productId, std::string(), std::string(), note.uid()); } addAttachments(msg, note.attachments(), attachmentCids); msg->assemble(); return msg->encodedContent().data(); } Note MIMEObject::readNote(const std::string &s) { return d->parseMimeMessage(s).value(); } std::string MIMEObject::writeContact(const Contact &contact, Version version, const std::string &pId) { ErrorHandler::clearErrors(); const std::string productId = getProductId(pId); KMime::Message::Ptr msg; Kolab::XMLObject xmlObject; const std::string xml = xmlObject.writeContact(contact, version, productId); Email preferredEmail = !contact.emailAddresses().empty() ? contact.emailAddresses().at(contact.emailAddressPreferredIndex()) : Email(); QPair pair = Conversion::fromMailto(preferredEmail.address()); std::string name = pair.second; std::string email = pair.first; if (name.empty()) { name = contact.name(); } if (version == KolabV3) { msg = Mime::createMessage(xCardMimeType(), contactKolabType(), xml, true, productId, email, name, contact.uid()); } else if (version == KolabV2) { msg = Mime::createMessage(contactKolabType(), contactKolabType(), xml, false, productId, email, name, contact.uid()); } msg->assemble(); return msg->encodedContent().data(); } Contact MIMEObject::readContact(const std::string &s) { return d->parseMimeMessage(s).value(); } std::string MIMEObject::writeDistlist(const DistList &distlist, Version version, const std::string &pId) { ErrorHandler::clearErrors(); const std::string productId = getProductId(pId); KMime::Message::Ptr msg; Kolab::XMLObject xmlObject; const std::string xml = xmlObject.writeDistlist(distlist, version, productId); if (version == KolabV3) { msg = Mime::createMessage(xCardMimeType(), distlistKolabType(), xml, true, productId, std::string(), std::string(), distlist.uid()); } else if (version == KolabV2) { msg = Mime::createMessage(distlistKolabType(), distlistKolabType(), xml, false, productId, std::string(), std::string(), distlist.uid()); } msg->assemble(); return msg->encodedContent().data(); } DistList MIMEObject::readDistlist(const std::string &s) { return d->parseMimeMessage(s).value(); } std::string MIMEObject::writeConfiguration(const Configuration &configuration, Version version, const std::string &pId) { ErrorHandler::clearErrors(); const std::string productId = getProductId(pId); KMime::Message::Ptr msg; Kolab::XMLObject xmlObject; const std::string xml = xmlObject.writeConfiguration(configuration, version, productId); std::string kolabType; switch (configuration.type()) { case Kolab::Configuration::TypeDictionary: kolabType = dictKolabType(); break; case Kolab::Configuration::TypeRelation: kolabType = relationKolabType(); break; case Kolab::Configuration::TypeSnippet: kolabType = configurationKolabType(); break; case Kolab::Configuration::TypeFileDriver: kolabType = configurationKolabType(); break; case Kolab::Configuration::TypeCategoryColor: kolabType = configurationKolabType(); break; default: break; } if (version == KolabV3) { msg = Mime::createMessage(kolabMimeType(), kolabType, xml, true, productId, std::string(), std::string(), configuration.uid()); } else if (version == KolabV2) { qCCritical(PIMKOLAB_LOG) << "Not available in KolabV2"; } msg->assemble(); return msg->encodedContent().data(); } Configuration MIMEObject::readConfiguration(const std::string &s) { return d->parseMimeMessage(s).value(); } std::string MIMEObject::writeFreebusy(const Freebusy &freebusy, Version version, const std::string &pId) { ErrorHandler::clearErrors(); const std::string productId = getProductId(pId); KMime::Message::Ptr msg; Kolab::XMLObject xmlObject; const std::string xml = xmlObject.writeFreebusy(freebusy, version, productId); if (version == KolabV3) { msg = Mime::createMessage(xCalMimeType(), freebusyKolabType(), xml, true, productId, std::string(), std::string(), freebusy.uid()); } else if (version == KolabV2) { qCCritical(PIMKOLAB_LOG) << "Not available in KolabV2"; } msg->assemble(); return msg->encodedContent().data(); } Freebusy MIMEObject::readFreebusy(const std::string &s) { return d->parseMimeMessage(s).value(); } } diff --git a/resources/kolab/pimkolab/kolabformat/v2helpers.cpp b/resources/kolab/pimkolab/kolabformat/v2helpers.cpp index b8ced6978..5a46ac62b 100644 --- a/resources/kolab/pimkolab/kolabformat/v2helpers.cpp +++ b/resources/kolab/pimkolab/kolabformat/v2helpers.cpp @@ -1,299 +1,299 @@ /* * Copyright (C) 2012 Christian Mollekopf * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program. If not, see . */ #include "v2helpers.h" #include "kolabdefinitions.h" #include "kolabformatV2/kolabbase.h" #include "kolabformatV2/journal.h" #include "kolabformatV2/task.h" #include "kolabformatV2/event.h" #include "kolabformatV2/contact.h" #include "kolabformatV2/distributionlist.h" #include "kolabformatV2/note.h" #include "mime/mimeutils.h" #include "pimkolab_debug.h" #include #include #include #include #include namespace Kolab { void getAttachments(KCalCore::Incidence::Ptr incidence, const QStringList &attachments, const KMime::Message::Ptr &mimeData) { if (!incidence) { qCCritical(PIMKOLAB_LOG) << "Invalid incidence"; return; } for (const QString &name : attachments) { QByteArray type; KMime::Content *content = Mime::findContentByName(mimeData, name, type); if (!content) { // guard against malformed events with non-existent attachments qCWarning(PIMKOLAB_LOG) <<"could not find attachment: "<< name.toUtf8() << type; continue; } const QByteArray c = content->decodedContent().toBase64(); KCalCore::Attachment::Ptr attachment(new KCalCore::Attachment(c, QString::fromLatin1(type))); attachment->setLabel(name); incidence->addAttachment(attachment); qCDebug(PIMKOLAB_LOG) << "ATTACHMENT NAME" << name << type; } } static QImage getPicture(const QString &pictureAttachmentName, const KMime::Message::Ptr &data, QByteArray &type) { if (!data) { qCCritical(PIMKOLAB_LOG) << "empty message"; return QImage(); } KMime::Content *imgContent = Mime::findContentByName(data, pictureAttachmentName /*"kolab-picture.png"*/, type); if (!imgContent) { qCWarning(PIMKOLAB_LOG) <<"could not find picture: " << pictureAttachmentName; return QImage(); } QByteArray imgData = imgContent->decodedContent(); QBuffer buffer(&imgData); buffer.open(QIODevice::ReadOnly); QImage image; bool success = false; if (type == "image/jpeg") { success = image.load(&buffer, "JPEG"); //FIXME I tried getting the code to interpret the picture as PNG, but the VCard implementation writes it as JPEG anyways... // if (success) { // QByteArray pic; // QBuffer b(&pic); // b.open(QIODevice::ReadWrite); // Q_ASSERT(image.save(&b, "PNG")); // b.close(); // Debug() << pic.toBase64(); // QBuffer b2(&pic); // b2.open(QIODevice::ReadOnly); // success = image.load(&b2, "PNG"); // b2.close(); // Q_ASSERT(success); // } } else { type = "image/png"; success = image.load(&buffer, "PNG"); } buffer.close(); if (!success) { qCWarning(PIMKOLAB_LOG) <<"failed to load picture"; } return image; } KContacts::Addressee addresseeFromKolab(const QByteArray &xmlData, const KMime::Message::Ptr &data) { if (!data) { qCCritical(PIMKOLAB_LOG) << "empty message"; return KContacts::Addressee(); } KContacts::Addressee addressee; // qCDebug(PIMKOLAB_LOG) << "xmlData " << xmlData; KolabV2::Contact contact(QString::fromUtf8(xmlData)); QByteArray type; const QString &pictureAttachmentName = contact.pictureAttachmentName(); if (!pictureAttachmentName.isEmpty()) { const QImage &img = getPicture(pictureAttachmentName, data, type); contact.setPicture(img, QString::fromLatin1(type)); } const QString &logoAttachmentName = contact.logoAttachmentName(); if (!logoAttachmentName.isEmpty()) { contact.setLogo(getPicture(logoAttachmentName, data, type), QString::fromLatin1(type)); } const QString &soundAttachmentName = contact.soundAttachmentName(); if (!soundAttachmentName.isEmpty()) { QByteArray type; KMime::Content *content = Mime::findContentByName(data, soundAttachmentName /*"sound"*/, type); if (content) { const QByteArray &sData = content->decodedContent(); contact.setSound(sData); } else { qCWarning(PIMKOLAB_LOG) <<"could not find sound: " << soundAttachmentName; } } contact.saveTo(&addressee); return addressee; } KContacts::Addressee addresseeFromKolab(const QByteArray &xmlData, QString &pictureAttachmentName, QString &logoAttachmentName, QString &soundAttachmentName) { KContacts::Addressee addressee; KolabV2::Contact contact(QString::fromUtf8(xmlData)); pictureAttachmentName = contact.pictureAttachmentName(); logoAttachmentName = contact.logoAttachmentName(); soundAttachmentName = contact.soundAttachmentName(); contact.saveTo(&addressee); return addressee; } static QByteArray createPicture(const QImage &img, const QString & /*format*/, QByteArray &type) { QByteArray pic; QBuffer buffer(&pic); buffer.open(QIODevice::WriteOnly); type = "image/png"; //FIXME it's not possible to save jpegs lossless, so we always use png. otherwise we would compress the image on every write. // if (format == "image/jpeg") { // type = "image/jpeg"; // img.save(&buffer, "JPEG"); // } else { img.save(&buffer, "PNG"); // } buffer.close(); return pic; } KMime::Message::Ptr contactToKolabFormat(const KolabV2::Contact &contact, const QString &productId) { KMime::Message::Ptr message = Mime::createMessage(QByteArray(KOLAB_TYPE_CONTACT), false, productId.toLatin1()); if (!message) { qCCritical(PIMKOLAB_LOG) << "empty message"; return KMime::Message::Ptr(); } message->subject()->fromUnicodeString(contact.uid(), "utf-8"); message->from()->fromUnicodeString(contact.fullEmail(), "utf-8"); KMime::Content *content = Mime::createMainPart(KOLAB_TYPE_CONTACT, contact.saveXML().toUtf8()); message->addContent(content); if (!contact.picture().isNull()) { QByteArray type; const QByteArray &pic = createPicture(contact.picture(), contact.pictureFormat(), type); content = Mime::createAttachmentPart(QByteArray(), type, /*"kolab-picture.png"*/ contact.pictureAttachmentName(), pic); message->addContent(content); } if (!contact.logo().isNull()) { QByteArray type; const QByteArray &pic = createPicture(contact.logo(), contact.logoFormat(), type); content = Mime::createAttachmentPart(QByteArray(), type, /*"kolab-logo.png"*/ contact.logoAttachmentName(), pic); message->addContent(content); } if (!contact.sound().isEmpty()) { content = Mime::createAttachmentPart(QByteArray(), "audio/unknown", /*"sound"*/ contact.soundAttachmentName(), contact.sound()); message->addContent(content); } message->assemble(); return message; } KContacts::ContactGroup contactGroupFromKolab(const QByteArray &xmlData) { KContacts::ContactGroup contactGroup; // qCDebug(PIMKOLAB_LOG) << "xmlData " << xmlData; KolabV2::DistributionList distList(QString::fromUtf8(xmlData)); distList.saveTo(&contactGroup); return contactGroup; } KMime::Message::Ptr distListToKolabFormat(const KolabV2::DistributionList &distList, const QString &productId) { KMime::Message::Ptr message = Mime::createMessage(KOLAB_TYPE_DISTLIST_V2, false, productId.toLatin1()); if (!message) { qCCritical(PIMKOLAB_LOG) << "empty message"; return KMime::Message::Ptr(); } message->subject()->fromUnicodeString(distList.uid(), "utf-8"); message->from()->fromUnicodeString(distList.uid(), "utf-8"); KMime::Content *content = Mime::createMainPart(KOLAB_TYPE_DISTLIST_V2, distList.saveXML().toUtf8()); message->addContent(content); message->assemble(); return message; } -KMime::Message::Ptr noteFromKolab(const QByteArray &xmlData, const KDateTime &creationDate) +KMime::Message::Ptr noteFromKolab(const QByteArray &xmlData, const QDateTime &creationDate) { KolabV2::Note j; if (!j.load(QString::fromUtf8(xmlData))) { qCWarning(PIMKOLAB_LOG) <<"failed to read note"; return KMime::Message::Ptr(); } Akonadi::NoteUtils::NoteMessageWrapper note; note.setTitle(j.summary()); note.setText(j.body()); note.setFrom(QStringLiteral("kolab@kde4")); - note.setCreationDate(creationDate.dateTime()); + note.setCreationDate(creationDate); return note.message(); } KMime::Message::Ptr noteToKolab(const KMime::Message::Ptr &msg, const QString &productId) { if (!msg) { qCCritical(PIMKOLAB_LOG) << "empty message"; return KMime::Message::Ptr(); } Akonadi::NoteUtils::NoteMessageWrapper note(msg); return Mime::createMessage(note.title(), QStringLiteral(KOLAB_TYPE_NOTE), QStringLiteral(KOLAB_TYPE_NOTE), noteToKolabXML(msg), false, productId); } QByteArray noteToKolabXML(const KMime::Message::Ptr &msg) { if (!msg) { qCCritical(PIMKOLAB_LOG) << "empty message"; return QByteArray(); } Akonadi::NoteUtils::NoteMessageWrapper note(msg); KolabV2::Note j; j.setSummary(note.title()); j.setBody(note.text()); return j.saveXML().toUtf8(); } QStringList readLegacyDictionaryConfiguration(const QByteArray &xmlData, QString &language) { QStringList dictionary; const QDomDocument xmlDoc = KolabV2::KolabBase::loadDocument(QString::fromUtf8(xmlData)); //TODO extract function from V2 format if (xmlDoc.isNull()) { qCCritical(PIMKOLAB_LOG) << "Failed to read the xml document"; return QStringList(); } QDomElement top = xmlDoc.documentElement(); if (top.tagName() != QLatin1String("configuration")) { qCWarning(PIMKOLAB_LOG) << QStringLiteral("XML error: Top tag was %1 instead of the expected configuration").arg(top.tagName()); return QStringList(); } for (QDomNode n = top.firstChild(); !n.isNull(); n = n.nextSibling()) { if (n.isComment() || !n.isElement()) { continue; } const QDomElement e = n.toElement(); const QString tagName = e.tagName(); if (tagName == QLatin1String("language")) { language = e.text(); } else if (tagName == QLatin1String("e")) { dictionary.append(e.text()); } } return dictionary; } } diff --git a/resources/kolab/pimkolab/kolabformat/v2helpers.h b/resources/kolab/pimkolab/kolabformat/v2helpers.h index cee440096..08403d079 100644 --- a/resources/kolab/pimkolab/kolabformat/v2helpers.h +++ b/resources/kolab/pimkolab/kolabformat/v2helpers.h @@ -1,100 +1,99 @@ /* * Copyright (C) 2012 Christian Mollekopf * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program. If not, see . */ #ifndef V2HELPERS_H #define V2HELPERS_H #include "kolabdefinitions.h" #include "kolabformatV2/kolabbase.h" #include "kolabformatV2/journal.h" #include "kolabformatV2/task.h" #include "kolabformatV2/event.h" #include "kolabformatV2/contact.h" #include "kolabformatV2/distributionlist.h" #include "kolabformatV2/note.h" #include "mime/mimeutils.h" #include "kolabformat/errorhandler.h" #include #include #include #include -#include #include #include #include #include namespace Kolab { /* * Parse XML, create KCalCore container and extract attachments */ template static KCalPtr fromXML(const QByteArray &xmlData, QStringList &attachments) { const QDomDocument xmlDoc = KolabV2::KolabBase::loadDocument(QString::fromUtf8(xmlData)); //TODO extract function from V2 format if (xmlDoc.isNull()) { Critical() << "Failed to read the xml document"; return KCalPtr(); } const KCalPtr i = Container::fromXml(xmlDoc, QString()); //For parsing we don't need the timezone, so we don't set one Q_ASSERT(i); const QDomNodeList nodes = xmlDoc.elementsByTagName(QStringLiteral("inline-attachment")); for (int i = 0; i < nodes.size(); i++) { attachments.append(nodes.at(i).toElement().text()); } return i; } void getAttachments(KCalCore::Incidence::Ptr incidence, const QStringList &attachments, const KMime::Message::Ptr &mimeData); template static inline IncidencePtr incidenceFromKolabImpl(const KMime::Message::Ptr &data, const QByteArray &mimetype, const QString &timezoneId) { KMime::Content *xmlContent = Mime::findContentByType(data, mimetype); if (!xmlContent) { Critical() << "couldn't find part"; return IncidencePtr(); } const QByteArray &xmlData = xmlContent->decodedContent(); QStringList attachments; IncidencePtr ptr = fromXML(xmlData, attachments); //TODO do we care about timezone? getAttachments(ptr, attachments, data); return ptr; } KContacts::Addressee addresseeFromKolab(const QByteArray &xmlData, const KMime::Message::Ptr &data); KContacts::Addressee addresseeFromKolab(const QByteArray &xmlData, QString &pictureAttachmentName, QString &logoAttachmentName, QString &soundAttachmentName); KMime::Message::Ptr contactToKolabFormat(const KolabV2::Contact &contact, const QString &productId); KContacts::ContactGroup contactGroupFromKolab(const QByteArray &xmlData); KMime::Message::Ptr distListToKolabFormat(const KolabV2::DistributionList &distList, const QString &productId); -KMime::Message::Ptr noteFromKolab(const QByteArray &xmlData, const KDateTime &creationDate); +KMime::Message::Ptr noteFromKolab(const QByteArray &xmlData, const QDateTime &creationDate); KMime::Message::Ptr noteToKolab(const KMime::Message::Ptr &msg, const QString &productId); QByteArray noteToKolabXML(const KMime::Message::Ptr &msg); QStringList readLegacyDictionaryConfiguration(const QByteArray &xmlData, QString &language); } #endif diff --git a/resources/kolab/pimkolab/kolabformat/xmlobject.cpp b/resources/kolab/pimkolab/kolabformat/xmlobject.cpp index 4032dd01f..7a9ecf2fa 100644 --- a/resources/kolab/pimkolab/kolabformat/xmlobject.cpp +++ b/resources/kolab/pimkolab/kolabformat/xmlobject.cpp @@ -1,376 +1,376 @@ /* * Copyright (C) 2012 Christian Mollekopf * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Affero General Public License for more details. * * You should have received a copy of the GNU Affero General Public License * along with this program. If not, see . */ #include "xmlobject.h" #include "v2helpers.h" #include "kolabformatV2/event.h" #include "conversion/kcalconversion.h" #include "conversion/kolabconversion.h" #include "conversion/commonconversion.h" #include "conversion/kabcconversion.h" #include #include "pimkolab_debug.h" namespace Kolab { static QString createUuid() { const QString uuid = QUuid::createUuid().toString(); return uuid.mid(1, uuid.size()-2); } XMLObject::XMLObject() { } std::string XMLObject::getSerializedUID() const { return mWrittenUID; } std::vector XMLObject::getAttachments() const { return mAttachments; } std::string XMLObject::writeEvent(const Event &event, Version version, const std::string &productId) { mWrittenUID.clear(); if (version == KolabV2) { const KCalCore::Event::Ptr i = Conversion::toKCalCore(event); if (!i) { qCCritical(PIMKOLAB_LOG) << "invalid incidence"; return std::string(); } if (i->uid().isEmpty()) { i->setUid(createUuid()); } mWrittenUID = Conversion::toStdString(i->uid()); //The timezone is used for created and last modified dates const QString &xml = KolabV2::Event::eventToXML(i, QStringLiteral("UTC")); return Conversion::toStdString(xml); } const std::string result = Kolab::writeEvent(event, productId); mWrittenUID = Kolab::getSerializedUID(); ErrorHandler::handleLibkolabxmlErrors(); return result; } Event XMLObject::readEvent(const std::string &s, Version version) { if (version == KolabV2) { QStringList attachments; const KCalCore::Event::Ptr event = Kolab::fromXML(QString::fromUtf8(s.c_str()).toUtf8(), attachments); if (!event || Kolab::ErrorHandler::errorOccured()) { qCCritical(PIMKOLAB_LOG) << "failed to read xml"; return Event(); } mAttachments.clear(); mAttachments.reserve(attachments.count()); foreach (const QString &attachment, attachments) { mAttachments.push_back(Conversion::toStdString(attachment)); } return Conversion::fromKCalCore(*event); } const Kolab::Event event = Kolab::readEvent(s, false); ErrorHandler::handleLibkolabxmlErrors(); return event; } std::string XMLObject::writeTodo(const Todo &event, Version version, const std::string &productId) { mWrittenUID.clear(); if (version == KolabV2) { const KCalCore::Todo::Ptr i = Conversion::toKCalCore(event); if (!i) { qCCritical(PIMKOLAB_LOG) << "invalid incidence"; return std::string(); } if (i->uid().isEmpty()) { i->setUid(createUuid()); } mWrittenUID = Conversion::toStdString(i->uid()); //The timezone is used for created and last modified dates const QString &xml = KolabV2::Task::taskToXML(i, QStringLiteral("UTC")); return Conversion::toStdString(xml); } const std::string result = Kolab::writeTodo(event, productId); mWrittenUID = Kolab::getSerializedUID(); ErrorHandler::handleLibkolabxmlErrors(); return result; } Todo XMLObject::readTodo(const std::string &s, Version version) { if (version == KolabV2) { QStringList attachments; const KCalCore::Todo::Ptr event = Kolab::fromXML(QString::fromUtf8(s.c_str()).toUtf8(), attachments); if (!event || Kolab::ErrorHandler::errorOccured()) { qCCritical(PIMKOLAB_LOG) << "failed to read xml"; return Todo(); } mAttachments.clear(); mAttachments.reserve(attachments.count()); foreach (const QString &attachment, attachments) { mAttachments.push_back(Conversion::toStdString(attachment)); } return Conversion::fromKCalCore(*event); } const Kolab::Todo todo = Kolab::readTodo(s, false); ErrorHandler::handleLibkolabxmlErrors(); return todo; } std::string XMLObject::writeJournal(const Journal &event, Version version, const std::string &productId) { mWrittenUID.clear(); if (version == KolabV2) { const KCalCore::Journal::Ptr i = Conversion::toKCalCore(event); if (!i) { qCCritical(PIMKOLAB_LOG) << "invalid journal"; return std::string(); } if (i->uid().isEmpty()) { i->setUid(createUuid()); } mWrittenUID = Conversion::toStdString(i->uid()); //The timezone is used for created and last modified dates const QString &xml = KolabV2::Journal::journalToXML(i, QStringLiteral("UTC")); return Conversion::toStdString(xml); } const std::string result = Kolab::writeJournal(event, productId); mWrittenUID = Kolab::getSerializedUID(); return result; } Journal XMLObject::readJournal(const std::string &s, Version version) { if (version == KolabV2) { QStringList attachments; const KCalCore::Journal::Ptr event = Kolab::fromXML(QString::fromUtf8(s.c_str()).toUtf8(), attachments); if (!event || Kolab::ErrorHandler::errorOccured()) { qCCritical(PIMKOLAB_LOG) << "failed to read xml"; return Journal(); } mAttachments.clear(); mAttachments.reserve(attachments.count()); foreach (const QString &attachment, attachments) { mAttachments.push_back(Conversion::toStdString(attachment)); } return Conversion::fromKCalCore(*event); } const Kolab::Journal journal = Kolab::readJournal(s, false); ErrorHandler::handleLibkolabxmlErrors(); return journal; } std::string XMLObject::writeFreebusy(const Freebusy &event, Version version, const std::string &productId) { mWrittenUID.clear(); if (version != KolabV3) { qCCritical(PIMKOLAB_LOG) << "only v3 implementation available"; return std::string(); } const std::string result = Kolab::writeFreebusy(event, productId); mWrittenUID = Kolab::getSerializedUID(); return result; } Freebusy XMLObject::readFreebusy(const std::string &s, Version version) { if (version != KolabV3) { qCCritical(PIMKOLAB_LOG) << "only v3 implementation available"; return Freebusy(); } return Kolab::readFreebusy(s, false); } std::string XMLObject::logoAttachmentName() const { return mLogoAttachmentName; } std::string XMLObject::pictureAttachmentName() const { return mPictureAttachmentName; } std::string XMLObject::soundAttachmentName() const { return mSoundAttachmentName; } Contact XMLObject::readContact(const std::string &s, Version version) { if (version == KolabV2) { const QByteArray xmlData(s.c_str(), s.size()); QString pictureAttachmentName; QString logoAttachmentName; QString soundAttachmentName; const KContacts::Addressee addressee = addresseeFromKolab(xmlData, pictureAttachmentName, logoAttachmentName, soundAttachmentName); mPictureAttachmentName = Conversion::toStdString(pictureAttachmentName); mLogoAttachmentName = Conversion::toStdString(logoAttachmentName); mSoundAttachmentName = Conversion::toStdString(soundAttachmentName); return Conversion::fromKABC(addressee); } const Kolab::Contact contact = Kolab::readContact(s, false); ErrorHandler::handleLibkolabxmlErrors(); return contact; } std::string XMLObject::writeContact(const Contact &contact, Version version, const std::string &productId) { mWrittenUID.clear(); if (version == KolabV2) { //FIXME attachment names are hardcoded for now KContacts::Addressee addressee = Conversion::toKABC(contact); if (addressee.uid().isEmpty()) { addressee.setUid(createUuid()); } mWrittenUID = Conversion::toStdString(addressee.uid()); const KolabV2::Contact contact(&addressee); return Conversion::toStdString(contact.saveXML()); } const std::string result = Kolab::writeContact(contact, productId); mWrittenUID = Kolab::getSerializedUID(); ErrorHandler::handleLibkolabxmlErrors(); return result; } DistList XMLObject::readDistlist(const std::string &s, Version version) { if (version == KolabV2) { const QByteArray xmlData(s.c_str(), s.size()); const KContacts::ContactGroup contactGroup = contactGroupFromKolab(xmlData); return Conversion::fromKABC(contactGroup); } const Kolab::DistList distlist = Kolab::readDistlist(s, false); ErrorHandler::handleLibkolabxmlErrors(); return distlist; } std::string XMLObject::writeDistlist(const DistList &distlist, Version version, const std::string &productId) { mWrittenUID.clear(); if (version == KolabV2) { KContacts::ContactGroup contactGroup = Conversion::toKABC(distlist); if (contactGroup.id().isEmpty()) { contactGroup.setId(createUuid()); } mWrittenUID = Conversion::toStdString(contactGroup.id()); const KolabV2::DistributionList d(&contactGroup); return Conversion::toStdString(d.saveXML()); } const std::string result = Kolab::writeDistlist(distlist, productId); mWrittenUID = Kolab::getSerializedUID(); ErrorHandler::handleLibkolabxmlErrors(); return result; } Note XMLObject::readNote(const std::string &s, Version version) { if (version == KolabV2) { - const KMime::Message::Ptr msg = noteFromKolab(QByteArray(s.c_str(), s.length()), KDateTime()); + const KMime::Message::Ptr msg = noteFromKolab(QByteArray(s.c_str(), s.length()), QDateTime()); if (!msg || Kolab::ErrorHandler::errorOccured()) { qCCritical(PIMKOLAB_LOG) << "failed to read xml"; return Note(); } return Conversion::fromNote(msg); } const Kolab::Note note = Kolab::readNote(s, false); ErrorHandler::handleLibkolabxmlErrors(); return note; } std::string XMLObject::writeNote(const Note ¬e, Version version, const std::string &productId) { mWrittenUID.clear(); if (version == KolabV2) { Note noteWithUID = note; if (noteWithUID.uid().empty()) { noteWithUID.setUid(Conversion::toStdString(createUuid())); } mWrittenUID = noteWithUID.uid(); const KMime::Message::Ptr n = Conversion::toNote(noteWithUID); const QByteArray &xml = noteToKolabXML(n); return std::string(xml.constData()); } const std::string result = Kolab::writeNote(note, productId); mWrittenUID = Kolab::getSerializedUID(); ErrorHandler::handleLibkolabxmlErrors(); return result; } Configuration XMLObject::readConfiguration(const std::string &s, Version version) { if (version == KolabV2) { QString lang; const QStringList dict = readLegacyDictionaryConfiguration(QByteArray(s.c_str(), s.length()), lang); if (lang.isEmpty()) { qCCritical(PIMKOLAB_LOG) << "not a dictionary or not a v2 configuration object"; return Kolab::Configuration(); } std::vector entries; entries.reserve(dict.size()); foreach (const QString &e, dict) { entries.push_back(Conversion::toStdString(e)); } Kolab::Dictionary dictionary(Conversion::toStdString(lang)); dictionary.setEntries(entries); return Configuration(dictionary); } const Kolab::Configuration configuration = Kolab::readConfiguration(s, false); ErrorHandler::handleLibkolabxmlErrors(); return configuration; } std::string XMLObject::writeConfiguration(const Configuration &configuration, Version version, const std::string &productId) { mWrittenUID.clear(); if (version != KolabV3) { qCCritical(PIMKOLAB_LOG) << "only v3 implementation available"; return std::string(); } const std::string result = Kolab::writeConfiguration(configuration, productId); mWrittenUID = Kolab::getSerializedUID(); ErrorHandler::handleLibkolabxmlErrors(); return result; } File XMLObject::readFile(const std::string &s, Version version) { if (version == KolabV2) { qCCritical(PIMKOLAB_LOG) << "only v3 implementation available"; return File(); } const Kolab::File file = Kolab::readFile(s, false); ErrorHandler::handleLibkolabxmlErrors(); return file; } std::string XMLObject::writeFile(const File &file, Version version, const std::string &productId) { mWrittenUID.clear(); if (version != KolabV3) { qCCritical(PIMKOLAB_LOG) << "only v3 implementation available"; return std::string(); } const std::string result = Kolab::writeFile(file, productId); mWrittenUID = Kolab::getSerializedUID(); ErrorHandler::handleLibkolabxmlErrors(); return result; } } diff --git a/resources/kolab/pimkolab/mime/mimeutils.cpp b/resources/kolab/pimkolab/mime/mimeutils.cpp index 756cded35..a895a3de4 100644 --- a/resources/kolab/pimkolab/mime/mimeutils.cpp +++ b/resources/kolab/pimkolab/mime/mimeutils.cpp @@ -1,224 +1,224 @@ /* * Copyright (C) 2012 Christian Mollekopf * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program. If not, see . */ #include "mimeutils.h" #include #include #include -#include +#include #include "kolabformat/kolabdefinitions.h" #include #include "libkolab-version.h" #include "pimkolab_debug.h" namespace Kolab { namespace Mime { KMime::Content *findContentByType(const KMime::Message::Ptr &data, const QByteArray &type) { if (type.isEmpty()) { qCCritical(PIMKOLAB_LOG) << "Empty type"; return nullptr; } Q_ASSERT(!data->contents().isEmpty()); Q_FOREACH (KMime::Content *c, data->contents()) { // qCDebug(PIMKOLAB_LOG) << c->contentType()->mimeType() << type; if (c->contentType()->mimeType() == type) { return c; } } return nullptr; } KMime::Content *findContentByName(const KMime::Message::Ptr &data, const QString &name, QByteArray &type) { Q_ASSERT(!data->contents().isEmpty()); Q_FOREACH (KMime::Content *c, data->contents()) { // qCDebug(PIMKOLAB_LOG) << "searching: " << c->contentType()->name().toUtf8(); if (c->contentType()->name() == name) { type = c->contentType()->mimeType(); return c; } } return nullptr; } KMime::Content *findContentById(const KMime::Message::Ptr &data, const QByteArray &id, QByteArray &type, QString &name) { if (id.isEmpty()) { qCCritical(PIMKOLAB_LOG) << "looking for empty cid"; return nullptr; } Q_ASSERT(!data->contents().isEmpty()); Q_FOREACH (KMime::Content *c, data->contents()) { // qCDebug(PIMKOLAB_LOG) << "searching: " << c->contentID()->identifier(); if (c->contentID()->identifier() == id) { type = c->contentType()->mimeType(); name = c->contentType()->name(); return c; } } return nullptr; } QList getContentMimeTypeList(const KMime::Message::Ptr &data) { QList typeList; Q_ASSERT(!data->contents().isEmpty()); typeList.reserve(data->contents().count()); Q_FOREACH (KMime::Content *c, data->contents()) { typeList.append(c->contentType()->mimeType()); } return typeList; } QString fromCid(const QString &cid) { if (cid.left(4) != QLatin1String("cid:")) { //Don't set if not a cid, happens when serializing format v2 return QString(); } return cid.right(cid.size()-4); } KMime::Message::Ptr createMessage(const QByteArray &mimetype, const QByteArray &xKolabType, const QByteArray &xml, bool v3, const QByteArray &productId, const QByteArray &fromEmail, const QString &fromName, const QString &subject) { KMime::Message::Ptr message = createMessage(xKolabType, v3, productId); message->subject()->fromUnicodeString(subject, "utf-8"); if (!fromEmail.isEmpty()) { KMime::Types::Mailbox mb; mb.setName(fromName); mb.setAddress(fromEmail); message->from()->addAddress(mb); } message->addContent(createMainPart(mimetype, xml)); return message; } KMime::Message::Ptr createMessage(const std::string &mimetype, const std::string &xKolabType, const std::string &xml, bool v3, const std::string &productId, const std::string &fromEmail, const std::string &fromName, const std::string &subject) { return createMessage(QByteArray(mimetype.c_str()), QByteArray(xKolabType.c_str()), QByteArray(xml.c_str()), v3, QByteArray(productId.data()), QByteArray(fromEmail.c_str()), QString::fromStdString(fromName), QString::fromStdString(subject)); } KMime::Message::Ptr createMessage(const QString &subject, const QString &mimetype, const QString &xKolabType, const QByteArray &xml, bool v3, const QString &prodid) { KMime::Message::Ptr message = createMessage(xKolabType.toLatin1(), v3, prodid.toLatin1()); if (!subject.isEmpty()) { message->subject()->fromUnicodeString(subject, "utf-8"); } KMime::Content *content = createMainPart(mimetype.toLatin1(), xml); message->addContent(content); message->assemble(); return message; } KMime::Content *createExplanationPart(bool v3) { Q_UNUSED(v3) KMime::Content *content = new KMime::Content(); content->contentType()->setMimeType("text/plain"); content->contentType()->setCharset("us-ascii"); content->contentTransferEncoding()->setEncoding(KMime::Headers::CE7Bit); content->setBody("This is a Kolab Groupware object.\n" "To view this object you will need an email client that can understand the Kolab Groupware format.\n" "For a list of such email clients please visit\n" "http://www.kolab.org/get-kolab\n"); return content; } KMime::Message::Ptr createMessage(const QByteArray &xKolabType, bool v3, const QByteArray &prodid) { KMime::Message::Ptr message(new KMime::Message); - message->date()->setDateTime(KDateTime::currentUtcDateTime().dateTime()); + message->date()->setDateTime(QDateTime::currentDateTimeUtc()); KMime::Headers::Generic *h = new KMime::Headers::Generic(X_KOLAB_TYPE_HEADER); h->fromUnicodeString(xKolabType, "utf-8"); message->appendHeader(h); if (v3) { KMime::Headers::Generic *hv3 = new KMime::Headers::Generic(X_KOLAB_MIME_VERSION_HEADER); hv3->fromUnicodeString(KOLAB_VERSION_V3, "utf-8"); message->appendHeader(hv3); } message->userAgent()->from7BitString(prodid); message->contentType()->setMimeType("multipart/mixed"); message->contentType()->setBoundary(KMime::multiPartBoundary()); message->addContent(createExplanationPart(v3)); return message; } KMime::Content *createMainPart(const QByteArray &mimeType, const QByteArray &decodedContent) { KMime::Content *content = new KMime::Content(); content->contentType()->setMimeType(mimeType); content->contentType()->setName(KOLAB_OBJECT_FILENAME, "us-ascii"); content->contentTransferEncoding()->setEncoding(KMime::Headers::CEquPr); content->contentDisposition()->setDisposition(KMime::Headers::CDattachment); content->contentDisposition()->setFilename(KOLAB_OBJECT_FILENAME); content->setBody(decodedContent); return content; } KMime::Content *createAttachmentPart(const QByteArray &cid, const QByteArray &mimeType, const QString &fileName, const QByteArray &base64EncodedContent) { KMime::Content *content = new KMime::Content(); if (!cid.isEmpty()) { content->contentID()->setIdentifier(cid); } content->contentType()->setMimeType(mimeType); content->contentType()->setName(fileName, "utf-8"); content->contentTransferEncoding()->setEncoding(KMime::Headers::CEbase64); content->contentDisposition()->setDisposition(KMime::Headers::CDattachment); content->contentDisposition()->setFilename(fileName); content->setBody(base64EncodedContent); return content; } Kolab::Attachment getAttachment(const std::string &id, const KMime::Message::Ptr &mimeData) { if (!QString::fromStdString(id).contains(QLatin1String("cid:"))) { qCCritical(PIMKOLAB_LOG) << "not a cid reference"; return Kolab::Attachment(); } QByteArray type; QString name; KMime::Content *content = findContentById(mimeData, fromCid(QString::fromStdString(id)).toLatin1(), type, name); if (!content) { // guard against malformed events with non-existent attachments qCCritical(PIMKOLAB_LOG) << "could not find attachment: "<< name << type; return Kolab::Attachment(); } // Debug() << id << content->decodedContent().toBase64().toStdString(); Kolab::Attachment attachment; attachment.setData(content->decodedContent().toStdString(), type.toStdString()); attachment.setLabel(name.toStdString()); return attachment; } Kolab::Attachment getAttachmentByName(const QString &name, const KMime::Message::Ptr &mimeData) { QByteArray type; KMime::Content *content = findContentByName(mimeData, name, type); if (!content) { // guard against malformed events with non-existent attachments qCWarning(PIMKOLAB_LOG) <<"could not find attachment: "<< name.toUtf8() << type; return Kolab::Attachment(); } Kolab::Attachment attachment; attachment.setData(content->decodedContent().toStdString(), type.toStdString()); attachment.setLabel(name.toStdString()); return attachment; } } //Namespace } //Namespace