diff --git a/framework/domain/mimetreeparser/interface.h b/framework/domain/mimetreeparser/interface.h index a9e394db..320030b7 100644 --- a/framework/domain/mimetreeparser/interface.h +++ b/framework/domain/mimetreeparser/interface.h @@ -1,327 +1,370 @@ /* Copyright (c) 2016 Sandro Knauß This library is free software; you can redistribute it and/or modify it under the terms of the GNU Library General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This library 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 Library General Public License for more details. You should have received a copy of the GNU Library General Public License along with this library; see the file COPYING.LIB. If not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #pragma once #include #include class Part; +typedef std::shared_ptr Part::Ptr; class EncryptionPart; +typedef std::shared_ptr EncryptionPart::Ptr; class SignaturePart; +typedef std::shared_ptr SignaturePart::Ptr; class MimePart; +typedef std::shared_ptr MimePart::Ptr; class MimePartPrivate; class ContentPart; +typedef std::shared_ptr ContentPart::Ptr; class ContentPartPrivate; class EncryptionErrorPart; +typedef std::shared_ptr EncryptionErrorPart::Ptr; class EncryptionErrorPartPrivate; class AttachmentPart; +typedef std::shared_ptr AttachmentPart::Ptr; class AttachmentPartPrivate; class EncapsulatedPart; +typedef std::shared_ptr EncapsulatedPart::Ptr; class EncapsulatedPart; class CertPart; -class CertPart; +typedef std::shared_ptr CertPart::Ptr; class Key; class Signature; class Encryption; class Parser; +typedef std::shared_ptr Parser::Ptr; class ParserPrivate; class Parser { public: Parser(const QByteArray &mimeMessage); - std::shared_ptr getPart(QUrl url); + Part::Ptr getPart(QUrl url); - QVector> collect() const; - QVector> collect() const; - QVector> collect(Part start, std::function select, std::function &)> filter) const; + QVector collect() const; + QVector collect() const; + QVector collect(Part start, std::function select, std::function filter) const; private: std::unique_ptr d; }; + class Part { public: virtual QByteArray type() const = 0; bool hasSubParts() const; - QList subParts() const; - Part partent() const; + QList subParts() const; + Part parent() const; + + virtual QVector signatures() const; + virtual QVector encryptions() const; }; +//A structure element, that we need to reflect, that there is a Encryption starts +// only add a new Encrption block to encryptions block +class EncryptionPart : public Part +{ +public: + QVector encryptions() const Q_DECL_OVERRIDE; + QByteArray type() const Q_DECL_OVERRIDE; +}; + +// A structure element, that we need to reflect, that there is a Signature starts +// only add a new Signature block to signature block +// With this we can a new Singature type like pep aka +/* + * add a bodypartformatter, that returns a PEPSignaturePart with all signed subparts that are signed with pep. + * subclass Signature aka PEPSignature to reflect different way of properties of PEPSignatures. + */ +class SignaturePart : public Part +{ +public: + QVector signatures() const Q_DECL_OVERRIDE; + QByteArray type() const Q_DECL_OVERRIDE; +}; + + + +class TextPart : public Part +{ +public: + QByteArray content() const; + + //Use default charset + QString encodedContent() const; + + // overwrite default charset with given charset + QString encodedContent(QByteArray charset) const; +} + /* * A MessagePart that is based on a KMime::Content */ -class MimePart : public Part +class MimePart : public TextPart { public: /** * Various possible values for the "Content-Disposition" header. */ enum Disposition { Invalid, ///< Default, invalid value Inline, ///< inline - Attachment, ///< attachment - Parallel ///< parallel (invalid, do not use) + Attachment ///< attachment }; // interessting header parts of a KMime::Content - QByteArray content() const; QMimeType mimetype() const; - Disposition dispossition() const + Disposition disposition() const; QUrl label() const; QByteArray cid() const; QByteArray charset() const; // we wanna overrwrite the charset of the content, because some clients set the charset wrong void setCharset(QByteArray charset); // Unique identifier to ecactly this KMime::Content QByteArray link() const; QByteArray type() const Q_DECL_OVERRIDE; private: std::unique_ptr d; }; /* * The main ContentPart * is MimePart a good parent class? * do we wanna need parts of the header of the connected KMime::Contents * usecases: * - * for htmlonly it is representating only one MimePart (ok) * for plaintext only also only one MimePart (ok) * for alternative, we are represating three messageparts * - "headers" do we return?, we can use setType to make it possible to select and than return these headers */ -class ContentPart : public MimePart +class MainContentPart : public MimePart { public: enum Types { PlainText, Html }; Q_DECLARE_FLAGS(Types, Type) - QByteArray content(Content::Type ct) const; - - // convert content with charset - QString content(Content::Type ct) const; + QVector content(Content::Type ct) const; Content::Types availableContent() const; - QVector signature() const; - QVector encryption() const; QByteArray type() const Q_DECL_OVERRIDE; private: std::unique_ptr d; }; Q_DECLARE_OPERATORS_FOR_FLAGS(ContentPart::Type) class AttachmentPart : public MimePart { public: QByteArray type() const Q_DECL_OVERRIDE; private: std::unique_ptr d; }; /* * Faild to decrypt part * thigs liks this can happen: * decryption in progress * have not tried at all to decrypt * wrong passphrase * no private key * cryptobackend is not configured correctly (no gpg available) * -> S/Mime and PGP have different meaning in their errors * * Open Questions: * - How to make the string translateable for multiple clients, so that multiple clients can show same error messages, * that helps users to understand what is going on ? * - Does openpgp have translations already? */ class EncryptionErrorPart : public Part { public: Error errorId() const; CryptoBackend cryptoBackend(); QByteArray type() const Q_DECL_OVERRIDE; private: std::unique_ptr d; }; /* * we want to request complete headers like: * from/to... */ class EncapsulatedPart :: public AttachmentPart { public: QByteArray type() const Q_DECL_OVERRIDE; QByteArray header(); private: std::unique_ptr d; }; /* * importing a cert GpgMe::ImportResult * checking a cert (if it is a valid cert) */ class CertPart :: public AttachmentPart { public: QByteArray type() const Q_DECL_OVERRIDE; bool checkCert() const; Status importCert() const; private: std::unique_ptr d; }; /* the ggme error class // class GPGMEPP_EXPORT ErrorImportResult { public: Error() : mErr(0), mMessage() {} explicit Error(unsigned int e) : mErr(e), mMessage() {} const char *source() const; const char *asString() const; int code() const; int sourceID() const; bool isCanceled() const; unsigned int encodedError() const { return mErr; } int toErrno() const; static bool hasSystemError(); static Error fromSystemError(unsigned int src = GPGMEPP_ERR_SOURCE_DEFAULT); static void setSystemError(gpg_err_code_t err); static void setErrno(int err); static Error fromErrno(int err, unsigned int src = GPGMEPP_ERR_SOURCE_DEFAULT); static Error fromCode(unsigned int err, unsigned int src = GPGMEPP_ERR_SOURCE_DEFAULT); GPGMEPP_MAKE_SAFE_BOOL_OPERATOR(mErr &&!isCanceled()) private: unsigned int mErr; mutable std::string mMessage; }; */ /* * a used smime/PGP key * in the end we also need things like: bool isRevokation() const; bool isInvalid() const; bool isExpired() const; -> so we end up wrapping GpgME::Key */ class Key { QString keyid() const; QString name() const; QString email() const; QString comment() const; QVector emails() const; KeyTrust keyTrust() const; CryptoBackend cryptoBackend() const; std::vector subkeys(); Key parentkey() const; }; class Signature { Key key() const; QDateTime creationDateTime() const; QDateTime expirationTime() const; bool neverExpires() const; bool inProgress(); //if the verfication is inProgress enum Validity { Unknown, Undefined, Never, Marginal, Full, Ultimate }; Validity validity() const; // to determine if we need this in our usecase (email) // GpgME::VerificationResult enum Summary { None = 0x000, Valid = 0x001, Green = 0x002, Red = 0x004, KeyRevoked = 0x008, KeyExpired = 0x010, SigExpired = 0x020, KeyMissing = 0x040, CrlMissing = 0x080, CrlTooOld = 0x100, BadPolicy = 0x200, SysError = 0x400 }; Summary summary() const; const char *policyURL() const; GpgME::Notation notation(unsigned int index) const; std::vector notations() const; }; /* * Normally the Keys for encryption are subkeys * for clients the parentkeys are "more interessting", because they store the name, email etc. * but a client may also wants show to what subkey the mail is really encrypted, an if this subkey isRevoked or something else */ class Encryption { std::vector recipients() const; }; \ No newline at end of file diff --git a/framework/domain/mimetreeparser/test.cpp b/framework/domain/mimetreeparser/test.cpp index e096ea78..51aa9871 100644 --- a/framework/domain/mimetreeparser/test.cpp +++ b/framework/domain/mimetreeparser/test.cpp @@ -1,146 +1,148 @@ Usecases: # plaintext msg + attachment * ContentPart => cp1 * AttachmentPart => ap1 (cp1) == collect(select=NoEncapsulatedMessages) (ap1) == collect(select=NoEncapsulatedMessages) (PlainText) == cp1.availableContent() # html msg + related attachment + normal attachment * ContentPart => cp1 * AttachmentPart(mimetype="*/related", cid="12345678") => ap1 * AttachmentPart => ap2 (cp1) == collect(select=NoEncapsulatedMessages) (ap1, ap2) == collect(select=NoEncapsulatedMessages) (ap2) == collect(select=NoEncapsulatedMessages, filter=filterelated) ap1 == getPart("cid:12345678") (Html) == cp1.availableContent() # alternative msg + attachment -* ContentPart(html="HTML", plaintext="Text") => cp1 +* ContentPart(html=[TextPart("HTML"),], plaintext=[TextPart("Text"),]) => cp1 * AttachmentPart => ap1 (cp1) == collect(select=NoEncapsulatedMessages) (ap1) == collect(select=NoEncapsulatedMessages) (Html, PlainText) == cp1.availableContent() -"HTML" == cp1.content(Html) -"text" == cp1.content(Plaintext) +[TextPart("HTML"),] == cp1.content(Html) +[TextPart("Text"),] == cp1.content(Plaintext) -# alternative msg with GPGInline -* ContentPart(html="HTML", plaintext="Text cypted") => cp1 - * TextPart(text="Text") - * TextPart(text=foo, encryption=(enc1) +# alternative msg with GPGInlin +* ContentPart( + plaintext=[TextPart("Text"), TextPart("foo", encryption=(enc1))], + html=[TextPart("HTML"),] + ) => cp1 (Html, PlainText) == cp1.availableContent() -TODO: but how to get plaintext/html content? +[TextPart("HTML"),] == cp1.content(Html) +[TextPart("Text"),TextPart("foo", encryption=(enc1))] == cp1.content(Plaintext) + # encrypted msg (not encrypted/error) with unencrypted attachment * EncryptionErrorPart => cp1 * AttachmentPart => ap1 (cp1) == collect(select=NoEncapsulatedMessages) (ap1) == collect(select=NoEncapsulatedMessages) #encrypted msg (decrypted with attachment) + unencrypted attachment * encrytion=(rec1,rec2) => enc1 * ContentPart(encrytion = (enc1,)) => cp1 * AttachmentPart(encryption = (enc1,)) => ap1 * AttachmentPart => ap2 (cp1) == collect(select=NoEncapsulatedMessages) (ap1, ap2) == collect(select=NoEncapsulatedMessages) #INLINE GPG encrypted msg + attachment -* ContentPart => cp1 - * TextPart - * TextPart(encrytion = (enc1(rec1,rec2),)) - * TextPart(signed = (sig1,)) - * TextPart +* ContentPart => cp1 with + plaintext=[TextPart, TextPart(encrytion = (enc1(rec1,rec2),)), TextPart(signed = (sig1,)), TextPart] * AttachmentPart => ap1 (cp1) == collect(select=NoEncapsulatedMessages) (ap1) == collect(select=NoEncapsulatedMessages) +[TextPart, TextPart(encrytion = (enc1(rec1,rec2),)), TextPart(signed = (sig1,)), TextPart] == cp1.content(Plaintext) + #forwared encrypted msg + attachments * ContentPart => cp1 * EncapsulatedPart => ep1 * Encrytion=(rec1,rec2) => enc1 * Signature => sig1 * ContentPart(encrytion = (enc1,), signature = (sig1,)) => cp2 * TextPart(encrytion = (enc1,), signature = (sig1,)) * TextPart(encrytion = (enc1, enc2(rec3,rec4),), signature = (sig1,)) * AttachmentPart(encrytion = (enc1,), signature = (sig1,)) => ap1 * AttachmentPart => ap2 (cp1) = collect(select=NoEncapsulatedMessages) (ap2) = collect(select=NoEncapsulatedMessages) (cp2) = collect(ep1, select=NoEncapsulatedMessages) (ap1) = collect(ep1, select=NoEncapsulatedMessages) (cp1, cp2) == collect() -(ap1, ap2) == collect() +(ap1, ap2) == collect()[TextPart, TextPart(encrytion = (enc1(rec1,rec2),)), TextPart(signed = (sig1,)), TextPart] # plaintext msg + attachment + cert * ContentPart => cp1 * AttachmentPart => ap1 * CertPart => cep1 (cp1) == collect(select=NoEncapsulatedMessages) (ap1, cep1) == collect(select=NoEncapsulatedMessages) (ap1) == collect(select=NoEncapsulatedMessages, filter=filterSubAttachmentParts) (cep1) == collect(select=NoEncapsulatedMessages) collect function: bool noEncapsulatedMessages(Part part) { if (is(part)) { return false; } return true; } bool filterRelated(T part) { if (part.mimetype == related && !part.cid.isEmpty()) { return false; //filter out related parts } return true; } bool filterSubAttachmentParts(AttachmentPart part) { if (isSubPart(part)) { return false; // filter out CertPart f.ex. } return true; } List collect(Part start, std::function select, std::function &)> filter) { List col; if (!select(start)) { return col; } if(isOrSubTypeIs(start) && filter(start.staticCast)){ col.append(p); } foreach(childs as child) { if (select(child)) { col.expand(collect(child,select,filter); } } return col; } \ No newline at end of file