diff --git a/messagecomposer/CMakeLists.txt b/messagecomposer/CMakeLists.txt index 87af2f068..0b250f6dd 100644 --- a/messagecomposer/CMakeLists.txt +++ b/messagecomposer/CMakeLists.txt @@ -1,54 +1,66 @@ set( CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${KDE4_ENABLE_EXCEPTIONS}" ) add_definitions( -DQT_NO_CAST_FROM_ASCII ) add_definitions( -DQT_NO_CAST_TO_ASCII ) add_subdirectory( tests ) set( messagecomposer_src composer.cpp - behaviour.cpp finalmessage.cpp util.cpp messagepart.cpp attachmentpart.cpp + globalpart.cpp infopart.cpp - skeletonmessagejob.cpp textpart.cpp - job.cpp - contentjob.cpp - maintextjob.cpp + jobbase.cpp + contentjobbase.cpp + singlepartjob.cpp multipartjob.cpp + maintextjob.cpp + + attachmentcompressjob.cpp + attachmentfrommimecontentjob.cpp + attachmentfrompublickeyjob.cpp + attachmentfromurljob.cpp + skeletonmessagejob.cpp ) include_directories( ${Boost_INCLUDE_DIR} ) kde4_add_library( messagecomposer SHARED ${messagecomposer_src} ) -target_link_libraries( messagecomposer ${KDE4_KIO_LIBS} kmime ) +target_link_libraries( messagecomposer ${KDE4_KIO_LIBS} kleo kmime kpimtextedit ) set_target_properties( messagecomposer PROPERTIES VERSION ${GENERIC_LIB_VERSION} SOVERSION ${GENERIC_LIB_SOVERSION} ) install( TARGETS messagecomposer EXPORT kdepimlibsLibraryTargets ${INSTALL_TARGETS_DEFAULT_ARGS} ) install( FILES messagecomposer_export.h composer.h - behaviour.h attachmentpart.h finalmessage.h + globalpart.h infopart.h messagepart.h - skeletonmessagejob.h textpart.h - job.h - contentjob.h - maintextjob.h + jobbase.h + contentjobbase.h + singlepartjob.h multipartjob.h + maintextjob.h + + attachmentcompressjob.h + attachmentfrommimecontentjob.h + attachmentfrompublickeyjob.h + attachmentfromurljob.h + skeletonmessagejob.h DESTINATION ${INCLUDE_INSTALL_DIR}/messagecomposer COMPONENT Devel ) diff --git a/messagecomposer/TODO.cberzan b/messagecomposer/TODO.cberzan index 6158e19b0..fcc46dfa7 100644 --- a/messagecomposer/TODO.cberzan +++ b/messagecomposer/TODO.cberzan @@ -1,26 +1,32 @@ 1) Make it work for plain text (including charset, word wrapping stuff) 2) Figure out headers (groups, display names, empty to:, local usernames, comments?) 3) HTML 4) Transport 5) Attachments 6) Signing & Crypto +tests at every step. Questions: * If multi-recipient-crypto, save all in sent-mail or just one unencrypted copy? KMail seems to save the encrypted stuff, but then how can it be decrypted without someone's private key? Or does KMail save a copy encrypted with my own key??? --> Now I think that's exactly what it does. * Why is KeyResolver in KMail and not kleopatra / libkleo??? * Can KMime::Message::Ptr be forward-declared somehow? * I have no clue how to make this extensible... and Behaviour is already a problem. * Disable copy constructors of jobs... * Should drafts be encrypted to self? * Figure out if MessagePart & family need to be qobjects at all... -* MessageComposer::Job and Akonadi::Job collide... -* The errors are defined in Job and Composer does not inherit that. I don't want - to make it inherit Job because it is really different from a Job (it doesn't - create a content, for starters). But then apps need to compare with - Job::SomeError instead of Composer::SomeError, and need to include job.h just for - that :-( +* copyright of composer is 1997, can I just say 'KMail authors'? +* rethink error reporting (and write DESIGN). There is KJobUiDelegate too! +* explain "outlook-compatible attachment names"... + +Random: * Think of where shared_ptrs should be used. +* Probably make us-ascii *and* utf-8 be "fallback" charsets. +* Plain text should still be 7bit if possible, even if html part has to be qupr. +* Consider adding a GlobalPart and JobBase::globalPart() that would return the composer's + GlobalPart. For things like charset, which are needed in MainTextJob for the texts, + SkeletonMessageJob for encoding the subject, and AttachmentJob for encoding things like + attachment names. Perhaps share the GUI stuff in JobBase the same way. +* The whole dummyComposer thing for jobs really annoys me :-/ diff --git a/messagecomposer/attachmentcompressjob.cpp b/messagecomposer/attachmentcompressjob.cpp new file mode 100644 index 000000000..c95614538 --- /dev/null +++ b/messagecomposer/attachmentcompressjob.cpp @@ -0,0 +1,176 @@ +/* + Copyright (c) 2009 Constantin Berzan + + Based on KMail code by: + Copyright (c) 1997 Markus Wuebben + + 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. +*/ + +#include "attachmentcompressjob.h" + +#include "attachmentpart.h" +#include "globalpart.h" +#include "jobbase_p.h" + +#include +#include + +#include +#include +#include +#include + +using namespace MessageComposer; + +class MessageComposer::AttachmentCompressJobPrivate : public JobBasePrivate +{ + public: + AttachmentCompressJobPrivate( AttachmentCompressJob *qq ); + + void doStart(); // slot + + const AttachmentPart *originalPart; + AttachmentPart *compressedPart; + bool warnCompressedSizeLarger; + + Q_DECLARE_PUBLIC( AttachmentCompressJob ) +}; + +AttachmentCompressJobPrivate::AttachmentCompressJobPrivate( AttachmentCompressJob *qq ) + : JobBasePrivate( qq ) + , originalPart( 0 ) + , compressedPart( 0 ) + , warnCompressedSizeLarger( true ) +{ +} + +void AttachmentCompressJobPrivate::doStart() +{ + Q_Q( AttachmentCompressJob ); + + Q_ASSERT( originalPart ); + QByteArray decoded = originalPart->data(); + + QByteArray array; + QBuffer dev( &array ); + KZip zip( &dev ); + if( !zip.open( QIODevice::WriteOnly ) ) { + q->setError( JobBase::BugError ); + q->setErrorText( i18n( "Could not initiate attachment compression." ) ); + q->emitResult(); + return; + } + + // Compress. + zip.setCompression( KZip::DeflateCompression ); + if( !zip.writeFile( originalPart->name(), QString( /*user*/ ), QString( /*group*/ ), + decoded.data(), decoded.size() ) ) { + q->setError( JobBase::BugError ); + q->setErrorText( i18n( "Could not compress the attachment." ) ); + q->emitResult(); + return; + } + zip.close(); + + // Check size. + if( warnCompressedSizeLarger && array.size() >= decoded.size() ) { + if( !q->globalPart()->isGuiEnabled() ) { + q->setError( JobBase::UserError ); + q->setErrorText( i18n( "The compressed attachment is larger than the original." ) ); + q->emitResult(); + return; + } else { + int result = KMessageBox::questionYesNo( q->globalPart()->parentWidgetForGui(), + i18n( "The compressed attachment is larger than the original. " + "Do you want to keep the original one?" ), + QString( /*caption*/ ), + KGuiItem( i18nc( "Do not compress", "Keep" ) ), + KGuiItem( i18n( "Compress" ) ) ); + if( result == KMessageBox::Yes ) { + q->setError( JobBase::UserCancelledError ); + q->setErrorText( i18n( "The user chose to keep the uncompressed file." ) ); + q->emitResult(); + return; + } + } + } + + // Create new part. + Q_ASSERT( compressedPart == 0 ); + compressedPart = new AttachmentPart; + compressedPart->setName( originalPart->name() + QString::fromLatin1( ".zip" ) ); + compressedPart->setDescription( originalPart->description() ); + compressedPart->setInline( originalPart->isInline() ); + compressedPart->setMimeType( "application/zip" ); + compressedPart->setCompressed( true ); + compressedPart->setEncrypted( originalPart->isEncrypted() ); + compressedPart->setSigned( originalPart->isSigned() ); + compressedPart->setData( array ); + q->emitResult(); // Success. + + // TODO consider adding a copy constructor to AttachmentPart. +} + + + +AttachmentCompressJob::AttachmentCompressJob( const AttachmentPart *part, QObject *parent ) + : JobBase( *new AttachmentCompressJobPrivate( this ), parent ) +{ + Q_D( AttachmentCompressJob ); + d->originalPart = part; +} + +AttachmentCompressJob::~AttachmentCompressJob() +{ +} + +void AttachmentCompressJob::start() +{ + QTimer::singleShot( 0, this, SLOT(doStart()) ); +} + +const AttachmentPart *AttachmentCompressJob::originalPart() const +{ + Q_D( const AttachmentCompressJob ); + return d->originalPart; +} + +void AttachmentCompressJob::setOriginalPart( const AttachmentPart *part ) +{ + Q_D( AttachmentCompressJob ); + d->originalPart = part; +} + +AttachmentPart *AttachmentCompressJob::compressedPart() const +{ + Q_D( const AttachmentCompressJob ); + return d->compressedPart; +} + +bool AttachmentCompressJob::warnCompressedSizeLarger() const +{ + Q_D( const AttachmentCompressJob ); + return d->warnCompressedSizeLarger; +} + +void AttachmentCompressJob::setWarnCompressedSizeLarger( bool warn ) +{ + Q_D( AttachmentCompressJob ); + d->warnCompressedSizeLarger = warn; +} + +#include "attachmentcompressjob.moc" diff --git a/messagecomposer/skeletonmessagejob.h b/messagecomposer/attachmentcompressjob.h similarity index 55% copy from messagecomposer/skeletonmessagejob.h copy to messagecomposer/attachmentcompressjob.h index b1b8eddd6..21a0971d7 100644 --- a/messagecomposer/skeletonmessagejob.h +++ b/messagecomposer/attachmentcompressjob.h @@ -1,63 +1,60 @@ /* Copyright (c) 2009 Constantin Berzan - Based on ideas by Stephen Kelly. 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. */ -#ifndef MESSAGECOMPOSER_SKELETONMESSAGEJOB_H -#define MESSAGECOMPOSER_SKELETONMESSAGEJOB_H +#ifndef MESSAGECOMPOSER_ATTACHMENTCOMPRESSJOB_H +#define MESSAGECOMPOSER_ATTACHMENTCOMPRESSJOB_H -#include "job.h" +#include "jobbase.h" #include "messagecomposer_export.h" -namespace KMime { - class Message; -} - namespace MessageComposer { -class SkeletonMessageJobPrivate; -class InfoPart; +class AttachmentCompressJobPrivate; +class AttachmentPart; /** - A message containing only the headers... */ -class MESSAGECOMPOSER_EXPORT SkeletonMessageJob : public Job +class MESSAGECOMPOSER_EXPORT AttachmentCompressJob : public JobBase { Q_OBJECT public: - explicit SkeletonMessageJob( InfoPart *infoPart = 0, QObject *parent = 0 ); - virtual ~SkeletonMessageJob(); + explicit AttachmentCompressJob( const AttachmentPart *part, QObject *parent = 0 ); + virtual ~AttachmentCompressJob(); - InfoPart *infoPart() const; - void setInfoPart( InfoPart *part ); + virtual void start(); - KMime::Message *message() const; - // TODO I think there is a way in C++ to make content() private, even if it's public - // in the base class. + const AttachmentPart *originalPart() const; + void setOriginalPart( const AttachmentPart *part ); + /// does not delete it unless it failed... + AttachmentPart *compressedPart() const; - protected Q_SLOTS: - virtual void process(); + // default true + bool warnCompressedSizeLarger() const; + void setWarnCompressedSizeLarger( bool warn ); private: - Q_DECLARE_PRIVATE( SkeletonMessageJob ) + Q_DECLARE_PRIVATE( AttachmentCompressJob ) + + Q_PRIVATE_SLOT( d_func(), void doStart() ) }; } // namespace MessageComposer #endif diff --git a/messagecomposer/attachmentfrommimecontentjob.cpp b/messagecomposer/attachmentfrommimecontentjob.cpp new file mode 100644 index 000000000..c7b2222d0 --- /dev/null +++ b/messagecomposer/attachmentfrommimecontentjob.cpp @@ -0,0 +1,122 @@ +/* + Copyright (c) 2009 Constantin Berzan + + Based on KMail code by: + Copyright (c) 1997 Markus Wuebben + + 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. +*/ + +#include "attachmentfrommimecontentjob.h" + +#include "attachmentpart.h" +#include "jobbase_p.h" + +#include + +#include + +#include "kmime/kmime_content.h" + +using namespace MessageComposer; +using KMime::Content; + +class MessageComposer::AttachmentFromMimeContentJobPrivate : public JobBasePrivate +{ + public: + AttachmentFromMimeContentJobPrivate( AttachmentFromMimeContentJob *qq ); + + void doStart(); // slot + + const Content *mimeContent; + QByteArray data; + AttachmentPart *part; + + Q_DECLARE_PUBLIC( AttachmentFromMimeContentJob ) +}; + +AttachmentFromMimeContentJobPrivate::AttachmentFromMimeContentJobPrivate( AttachmentFromMimeContentJob *qq ) + : JobBasePrivate( qq ) + , part( 0 ) +{ +} + +void AttachmentFromMimeContentJobPrivate::doStart() +{ + Q_Q( AttachmentFromMimeContentJob ); + + // Create the AttachmentPart. + Q_ASSERT( part == 0 ); + part = new AttachmentPart; + Content *content = const_cast( mimeContent ); + part->setData( content->decodedContent() ); + + // Get the details from the MIME headers. + if( content->contentType( false ) ) { + part->setMimeType( content->contentType()->mimeType() ); + part->setName( content->contentType()->name() ); + } + if( content->contentTransferEncoding( false ) ) { + part->setEncoding( content->contentTransferEncoding()->encoding() ); + } + if( content->contentDisposition( false ) ) { + //part->setFileName( content->contentDisposition()->filename() ); TODO support filename + part->setInline( content->contentDisposition()->disposition() == KMime::Headers::CDinline ); + } + if( content->contentDescription( false ) ) { + part->setDescription( content->contentDescription()->asUnicodeString() ); + } + + q->emitResult(); // Success. +} + + + +AttachmentFromMimeContentJob::AttachmentFromMimeContentJob( const Content *content, QObject *parent ) + : JobBase( *new AttachmentFromMimeContentJobPrivate( this ), parent ) +{ + Q_D( AttachmentFromMimeContentJob ); + d->mimeContent = content; +} + +AttachmentFromMimeContentJob::~AttachmentFromMimeContentJob() +{ +} + +void AttachmentFromMimeContentJob::start() +{ + QTimer::singleShot( 0, this, SLOT(doStart()) ); +} + +const Content *AttachmentFromMimeContentJob::mimeContent() const +{ + Q_D( const AttachmentFromMimeContentJob ); + return d->mimeContent; +} + +void AttachmentFromMimeContentJob::setMimeContent( const Content *content ) +{ + Q_D( AttachmentFromMimeContentJob ); + d->mimeContent = content; +} + +AttachmentPart *AttachmentFromMimeContentJob::attachmentPart() const +{ + Q_D( const AttachmentFromMimeContentJob ); + return d->part; +} + +#include "attachmentfrommimecontentjob.moc" diff --git a/messagecomposer/skeletonmessagejob.h b/messagecomposer/attachmentfrommimecontentjob.h similarity index 57% copy from messagecomposer/skeletonmessagejob.h copy to messagecomposer/attachmentfrommimecontentjob.h index b1b8eddd6..0d9f2780f 100644 --- a/messagecomposer/skeletonmessagejob.h +++ b/messagecomposer/attachmentfrommimecontentjob.h @@ -1,63 +1,61 @@ /* Copyright (c) 2009 Constantin Berzan - Based on ideas by Stephen Kelly. 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. */ -#ifndef MESSAGECOMPOSER_SKELETONMESSAGEJOB_H -#define MESSAGECOMPOSER_SKELETONMESSAGEJOB_H +#ifndef MESSAGECOMPOSER_ATTACHMENTFROMMIMECONTENT_H +#define MESSAGECOMPOSER_ATTACHMENTFROMMIMECONTENT_H -#include "job.h" +#include "jobbase.h" #include "messagecomposer_export.h" namespace KMime { - class Message; + class Content; } namespace MessageComposer { -class SkeletonMessageJobPrivate; -class InfoPart; +class AttachmentFromMimeContentJobPrivate; +class AttachmentPart; /** - A message containing only the headers... */ -class MESSAGECOMPOSER_EXPORT SkeletonMessageJob : public Job +class MESSAGECOMPOSER_EXPORT AttachmentFromMimeContentJob : public JobBase { Q_OBJECT public: - explicit SkeletonMessageJob( InfoPart *infoPart = 0, QObject *parent = 0 ); - virtual ~SkeletonMessageJob(); + explicit AttachmentFromMimeContentJob( const KMime::Content *content, QObject *parent = 0 ); + virtual ~AttachmentFromMimeContentJob(); - InfoPart *infoPart() const; - void setInfoPart( InfoPart *part ); + virtual void start(); - KMime::Message *message() const; - // TODO I think there is a way in C++ to make content() private, even if it's public - // in the base class. + const KMime::Content *mimeContent() const; + void setMimeContent( const KMime::Content *content ); - protected Q_SLOTS: - virtual void process(); + /// does not delete it unless it failed... + AttachmentPart *attachmentPart() const; private: - Q_DECLARE_PRIVATE( SkeletonMessageJob ) + Q_DECLARE_PRIVATE( AttachmentFromMimeContentJob ) + + Q_PRIVATE_SLOT( d_func(), void doStart() ) }; } // namespace MessageComposer #endif diff --git a/messagecomposer/attachmentfrompublickeyjob.cpp b/messagecomposer/attachmentfrompublickeyjob.cpp new file mode 100644 index 000000000..d7da4df47 --- /dev/null +++ b/messagecomposer/attachmentfrompublickeyjob.cpp @@ -0,0 +1,152 @@ +/* + Copyright (c) 2009 Constantin Berzan + + Based on KMail code by: + Copyright (c) 1997 Markus Wuebben + + 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. +*/ + +#include "attachmentfrompublickeyjob.h" + +#include "attachmentpart.h" +#include "globalpart.h" +#include "jobbase_p.h" + +#include + +#include +#include + +#include +#include +#include + +using namespace MessageComposer; + +class MessageComposer::AttachmentFromPublicKeyJobPrivate : public JobBasePrivate +{ + public: + AttachmentFromPublicKeyJobPrivate( AttachmentFromPublicKeyJob *qq ); + + void doStart(); // slot + void exportResult( const GpgME::Error &error, const QByteArray &keyData ); // slot + void emitGpgError( const GpgME::Error &error ); + + QString fingerprint; + QByteArray data; + AttachmentPart *part; + + Q_DECLARE_PUBLIC( AttachmentFromPublicKeyJob ) +}; + +AttachmentFromPublicKeyJobPrivate::AttachmentFromPublicKeyJobPrivate( AttachmentFromPublicKeyJob *qq ) + : JobBasePrivate( qq ) + , part( 0 ) +{ +} + +void AttachmentFromPublicKeyJobPrivate::doStart() +{ + Q_Q( AttachmentFromPublicKeyJob ); + + Kleo::ExportJob *job = Kleo::CryptoBackendFactory::instance()->openpgp()->publicKeyExportJob( true ); + Q_ASSERT( job ); + QObject::connect( job, SIGNAL(result(GpgME::Error,QByteArray)), + q, SLOT(exportResult(GpgME::Error,QByteArray)) ); + + const GpgME::Error error = job->start( QStringList( fingerprint ) ); + if( error ) { + emitGpgError( error ); + // TODO check autodeletion policy of Kleo::Jobs... + return; + } else if( q->globalPart()->isGuiEnabled() ) { + (void)new Kleo::ProgressDialog( job, i18n( "Exporting key..." ), + q->globalPart()->parentWidgetForGui() ); + } +} + +void AttachmentFromPublicKeyJobPrivate::exportResult( const GpgME::Error &error, const QByteArray &keyData ) +{ + Q_Q( AttachmentFromPublicKeyJob ); + + if( error ) { + emitGpgError( error ); + return; + } + + // Create the AttachmentPart. + Q_ASSERT( part == 0 ); + part = new AttachmentPart; + part->setName( i18n( "OpenPGP key 0x%1", fingerprint ) ); + part->setFileName( QString::fromLatin1( "0x" + fingerprint.toLatin1() + ".asc" ) ); + part->setMimeType( "application/pgp-keys" ); + part->setData( keyData ); + + q->emitResult(); // Success. +} + +void AttachmentFromPublicKeyJobPrivate::emitGpgError( const GpgME::Error &error ) +{ + Q_Q( AttachmentFromPublicKeyJob ); + + Q_ASSERT( error ); + const QString msg = i18n( "

An error occurred while trying to export " + "the key from the backend:

" + "

%1

", + QString::fromLocal8Bit( error.asString() ) ); + q->setError( JobBase::UserError ); + q->setErrorText( msg ); + q->emitResult(); +} + + + +AttachmentFromPublicKeyJob::AttachmentFromPublicKeyJob( const QString &fingerprint, QObject *parent ) + : JobBase( *new AttachmentFromPublicKeyJobPrivate( this ), parent ) +{ + Q_D( AttachmentFromPublicKeyJob ); + d->fingerprint = fingerprint; +} + +AttachmentFromPublicKeyJob::~AttachmentFromPublicKeyJob() +{ +} + +void AttachmentFromPublicKeyJob::start() +{ + QTimer::singleShot( 0, this, SLOT(doStart()) ); +} + +QString AttachmentFromPublicKeyJob::fingerprint() const +{ + Q_D( const AttachmentFromPublicKeyJob ); + return d->fingerprint; +} + +void AttachmentFromPublicKeyJob::setFingerprint( const QString &fingerprint ) +{ + Q_D( AttachmentFromPublicKeyJob ); + d->fingerprint = fingerprint; +} + +AttachmentPart *AttachmentFromPublicKeyJob::attachmentPart() const +{ + Q_D( const AttachmentFromPublicKeyJob ); + return d->part; +} + +#include "attachmentfrompublickeyjob.moc" diff --git a/messagecomposer/skeletonmessagejob.h b/messagecomposer/attachmentfrompublickeyjob.h similarity index 53% copy from messagecomposer/skeletonmessagejob.h copy to messagecomposer/attachmentfrompublickeyjob.h index b1b8eddd6..67c73c514 100644 --- a/messagecomposer/skeletonmessagejob.h +++ b/messagecomposer/attachmentfrompublickeyjob.h @@ -1,63 +1,59 @@ /* Copyright (c) 2009 Constantin Berzan - Based on ideas by Stephen Kelly. 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. */ -#ifndef MESSAGECOMPOSER_SKELETONMESSAGEJOB_H -#define MESSAGECOMPOSER_SKELETONMESSAGEJOB_H +#ifndef MESSAGECOMPOSER_ATTACHMENTFROMPUBLICKEY_H +#define MESSAGECOMPOSER_ATTACHMENTFROMPUBLICKEY_H -#include "job.h" +#include "jobbase.h" #include "messagecomposer_export.h" -namespace KMime { - class Message; -} - namespace MessageComposer { -class SkeletonMessageJobPrivate; -class InfoPart; +class AttachmentFromPublicKeyJobPrivate; +class AttachmentPart; /** - A message containing only the headers... */ -class MESSAGECOMPOSER_EXPORT SkeletonMessageJob : public Job +// TODO I have no idea how to test this. Have a fake keyring??? +class MESSAGECOMPOSER_EXPORT AttachmentFromPublicKeyJob : public JobBase { Q_OBJECT public: - explicit SkeletonMessageJob( InfoPart *infoPart = 0, QObject *parent = 0 ); - virtual ~SkeletonMessageJob(); + explicit AttachmentFromPublicKeyJob( const QString &fingerprint, QObject *parent = 0 ); + virtual ~AttachmentFromPublicKeyJob(); - InfoPart *infoPart() const; - void setInfoPart( InfoPart *part ); + virtual void start(); - KMime::Message *message() const; - // TODO I think there is a way in C++ to make content() private, even if it's public - // in the base class. + QString fingerprint() const; + void setFingerprint( const QString &fingerprint ); - protected Q_SLOTS: - virtual void process(); + /// does not delete it unless it failed... + AttachmentPart *attachmentPart() const; private: - Q_DECLARE_PRIVATE( SkeletonMessageJob ) + Q_DECLARE_PRIVATE( AttachmentFromPublicKeyJob ) + + Q_PRIVATE_SLOT( d_func(), void doStart() ) + Q_PRIVATE_SLOT( d_func(), void exportResult( GpgME::Error, QByteArray ) ) }; } // namespace MessageComposer #endif diff --git a/messagecomposer/attachmentfromurljob.cpp b/messagecomposer/attachmentfromurljob.cpp new file mode 100644 index 000000000..2e9dfb894 --- /dev/null +++ b/messagecomposer/attachmentfromurljob.cpp @@ -0,0 +1,185 @@ +/* + Copyright (c) 2009 Constantin Berzan + + Based on KMail code by: + Copyright (c) 1997 Markus Wuebben + + 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. +*/ + +#include "attachmentfromurljob.h" + +#include "attachmentpart.h" +#include "globalpart.h" +#include "jobbase_p.h" + +#include +#include + +#include +#include +#include +#include +#include + +using namespace MessageComposer; + +class MessageComposer::AttachmentFromUrlJobPrivate : public JobBasePrivate +{ + public: + AttachmentFromUrlJobPrivate( AttachmentFromUrlJob *qq ); + + void doStart(); // slot + void transferJobData( KIO::Job *job, const QByteArray &jobData ); + void transferJobResult( KJob *job ); + + KUrl url; + qint64 maxSize; + QByteArray data; + AttachmentPart *part; + + Q_DECLARE_PUBLIC( AttachmentFromUrlJob ) +}; + +AttachmentFromUrlJobPrivate::AttachmentFromUrlJobPrivate( AttachmentFromUrlJob *qq ) + : JobBasePrivate( qq ) + , maxSize( -1 ) + , part( 0 ) +{ +} + +void AttachmentFromUrlJobPrivate::doStart() +{ + Q_Q( AttachmentFromUrlJob ); + + if( !url.isValid() ) { + q->setError( JobBase::UserError ); + q->setErrorText( i18n( "\"%1\" not found. Please specify the full path.", url.prettyUrl() ) ); + q->emitResult(); + return; + } + + if( maxSize != -1 && url.isLocalFile() ) { + const qint64 size = QFileInfo( url.toLocalFile() ).size(); + if( size > maxSize ) { + q->setError( JobBase::UserError ); + q->setErrorText( i18n( "You may not attach files bigger than %1.", + KGlobal::locale()->formatByteSize( maxSize ) ) ); + q->emitResult(); + return; + } + } + + Q_ASSERT( data.isEmpty() ); // Not started twice. + KIO::TransferJob *tjob = KIO::get( url, KIO::NoReload, + ( q->globalPart()->isGuiEnabled() ? KIO::DefaultFlags : KIO::HideProgressInfo ) ); + KIO::Scheduler::scheduleJob( tjob ); + QObject::connect( tjob, SIGNAL(result(KJob*)), q, SLOT(transferJobResult(KJob*)) ); + QObject::connect( tjob, SIGNAL(data(KIO::Job*,QByteArray)), + q, SLOT(transferJobData(KIO::Job*,QByteArray)) ); +} + +void AttachmentFromUrlJobPrivate::transferJobData( KIO::Job *job, const QByteArray &jobData ) +{ + Q_UNUSED( job ); + data += jobData; + // TODO original code used a QBuffer; why? +} + +void AttachmentFromUrlJobPrivate::transferJobResult( KJob *job ) +{ + Q_Q( AttachmentFromUrlJob ); + + if( job->error() ) { + // TODO this loses useful stuff from KIO, like detailed error descriptions, causes+solutions, + // ... use UiDelegate somehow? + q->setError( job->error() ); + q->setErrorText( job->errorString() ); + q->emitResult(); + return; + } + + Q_ASSERT( dynamic_cast( job ) ); + KIO::TransferJob *tjob = static_cast( job ); + + // Determine the MIME type and filename of the attachment. + QString mimeType = tjob->mimetype(); + kDebug() << "Mimetype is" << tjob->mimetype(); + QString filename = url.fileName(); + if( filename.isEmpty() ) { + filename = i18nc( "a file called 'unknown.ext'", "unknown%1", + KMimeType::mimeType( mimeType )->mainExtension() ); + } + + // Create the AttachmentPart. + Q_ASSERT( part == 0 ); + part = new AttachmentPart; + part->setMimeType( mimeType.toLatin1() ); + part->setName( filename ); + part->setFileName( filename ); + part->setData( data ); + q->emitResult(); // Success. +} + + + +AttachmentFromUrlJob::AttachmentFromUrlJob( const KUrl &url, QObject *parent ) + : JobBase( *new AttachmentFromUrlJobPrivate( this ), parent ) +{ + Q_D( AttachmentFromUrlJob ); + d->url = url; +} + +AttachmentFromUrlJob::~AttachmentFromUrlJob() +{ +} + +void AttachmentFromUrlJob::start() +{ + QTimer::singleShot( 0, this, SLOT(doStart()) ); +} + +KUrl AttachmentFromUrlJob::url() const +{ + Q_D( const AttachmentFromUrlJob ); + return d->url; +} + +void AttachmentFromUrlJob::setUrl( const KUrl &url ) +{ + Q_D( AttachmentFromUrlJob ); + d->url = url; +} + +qint64 AttachmentFromUrlJob::maximumAllowedSize() const +{ + Q_D( const AttachmentFromUrlJob ); + return d->maxSize; +} + +void AttachmentFromUrlJob::setMaximumAllowedSize( qint64 size ) +{ + Q_D( AttachmentFromUrlJob ); + d->maxSize = size; +} + +AttachmentPart *AttachmentFromUrlJob::attachmentPart() const +{ + Q_D( const AttachmentFromUrlJob ); + return d->part; +} + +#include "attachmentfromurljob.moc" diff --git a/messagecomposer/attachmentpart.h b/messagecomposer/attachmentfromurljob.h similarity index 53% copy from messagecomposer/attachmentpart.h copy to messagecomposer/attachmentfromurljob.h index 6a15c8528..b2c2d3929 100644 --- a/messagecomposer/attachmentpart.h +++ b/messagecomposer/attachmentfromurljob.h @@ -1,58 +1,63 @@ /* Copyright (c) 2009 Constantin Berzan 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. */ -#ifndef MESSAGECOMPOSER_ATTACHMENTPART_H -#define MESSAGECOMPOSER_ATTACHMENTPART_H +#ifndef MESSAGECOMPOSER_ATTACHMENTFROMURLJOB_H +#define MESSAGECOMPOSER_ATTACHMENTFROMURLJOB_H -#include "messagepart.h" +#include "jobbase.h" +#include "messagecomposer_export.h" -#include - -class KUrl; +#include namespace MessageComposer { -/** setOverrideTransferEncoding for an AttachmentPart means setting the CTE for the sub-Content - representing this attachment */ -class MESSAGECOMPOSER_EXPORT AttachmentPart : public MessagePart +class AttachmentFromUrlJobPrivate; +class AttachmentPart; + +/** +*/ +class MESSAGECOMPOSER_EXPORT AttachmentFromUrlJob : public JobBase { Q_OBJECT public: - typedef QList List; + explicit AttachmentFromUrlJob( const KUrl &url = KUrl(), QObject *parent = 0 ); + virtual ~AttachmentFromUrlJob(); - explicit AttachmentPart( QObject *parent = 0 ); - virtual ~AttachmentPart(); + virtual void start(); KUrl url() const; void setUrl( const KUrl &url ); - - bool isDataLoaded() const; - bool loadData(); + qint64 maximumAllowedSize() const; + void setMaximumAllowedSize( qint64 size ); - // TODO handle mime type; charset for textual types, etc. + /// does not delete it unless it failed... + AttachmentPart *attachmentPart() const; private: - class Private; - Private *const d; + Q_DECLARE_PRIVATE( AttachmentFromUrlJob ) + + Q_PRIVATE_SLOT( d_func(), void doStart() ) + Q_PRIVATE_SLOT( d_func(), void transferJobData( KIO::Job*, QByteArray ) ) + Q_PRIVATE_SLOT( d_func(), void transferJobResult( KJob* ) ) }; } // namespace MessageComposer -#endif // MESSAGECOMPOSER_INFOPART_H +#endif diff --git a/messagecomposer/attachmentpart.cpp b/messagecomposer/attachmentpart.cpp index 6110b6fc6..3a417aac9 100644 --- a/messagecomposer/attachmentpart.cpp +++ b/messagecomposer/attachmentpart.cpp @@ -1,68 +1,189 @@ /* Copyright (c) 2009 Constantin Berzan 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. */ #include "attachmentpart.h" +#include "util.h" + +#include #include using namespace MessageComposer; class MessageComposer::AttachmentPart::Private { public: - KUrl url; - bool dataLoaded; + QString name; + QString fileName; + QString description; + bool isInline; + bool autoEncoding; + KMime::Headers::contentEncoding encoding; + QByteArray mimeType; + bool compressed; + bool toEncrypt; + bool toSign; QByteArray data; + qint64 size; }; AttachmentPart::AttachmentPart( QObject *parent ) : MessagePart( parent ) , d( new Private ) { - d->dataLoaded = false; + d->isInline = false; + d->autoEncoding = true; + d->encoding = KMime::Headers::CE7Bit; + d->compressed = false; + d->toEncrypt = false; + d->toSign = false; + d->size = -1; } AttachmentPart::~AttachmentPart() { delete d; } -KUrl AttachmentPart::url() const +QString AttachmentPart::name() const +{ + return d->name; +} + +void AttachmentPart::setName( const QString &name ) +{ + d->name = name; +} + +QString AttachmentPart::fileName() const +{ + return d->fileName; +} + +void AttachmentPart::setFileName( const QString &name ) +{ + d->fileName = name; +} + +QString AttachmentPart::description() const +{ + return d->description; +} + +void AttachmentPart::setDescription( const QString &description ) +{ + d->description = description; +} + +bool AttachmentPart::isInline() const +{ + return d->isInline; +} + +void AttachmentPart::setInline( bool inl ) +{ + d->isInline = inl; +} + +bool AttachmentPart::isAutoEncoding() const +{ + return d->autoEncoding; +} + +void AttachmentPart::setAutoEncoding( bool enabled ) +{ + d->autoEncoding = enabled; + if( enabled ) { + d->encoding = encodingsForData( d->data ).first(); + } + d->size = sizeWithEncoding( d->data, d->encoding ); +} + +KMime::Headers::contentEncoding AttachmentPart::encoding() const +{ + return d->encoding; +} + +void AttachmentPart::setEncoding( KMime::Headers::contentEncoding encoding ) +{ + d->autoEncoding = false; + d->encoding = encoding; + d->size = sizeWithEncoding( d->data, d->encoding ); +} + +QByteArray AttachmentPart::mimeType() const +{ + return d->mimeType; +} + +void AttachmentPart::setMimeType( const QByteArray &mimeType ) +{ + d->mimeType = mimeType; +} + +bool AttachmentPart::isCompressed() const +{ + return d->compressed; +} + +void AttachmentPart::setCompressed( bool compressed ) +{ + d->compressed = compressed; +} + +bool AttachmentPart::isEncrypted() const +{ + return d->toEncrypt; +} + +void AttachmentPart::setEncrypted( bool encrypted ) +{ + d->toEncrypt = encrypted; +} + +bool AttachmentPart::isSigned() const +{ + return d->toSign; +} + +void AttachmentPart::setSigned( bool sign ) { - return d->url; + d->toSign = sign; } -void AttachmentPart::setUrl( const KUrl &url ) +QByteArray AttachmentPart::data() const { - d->url = url; - d->dataLoaded = false; + return d->data; } -bool AttachmentPart::isDataLoaded() const +void AttachmentPart::setData( const QByteArray &data ) { - return d->dataLoaded; + d->data = data; + if( d->autoEncoding ) { + d->encoding = encodingsForData( data ).first(); + }; + d->size = sizeWithEncoding( d->data, d->encoding ); } -bool AttachmentPart::loadData() +qint64 AttachmentPart::size() const { - // TODO - return false; + return d->size; } #include "attachmentpart.moc" diff --git a/messagecomposer/attachmentpart.h b/messagecomposer/attachmentpart.h index 6a15c8528..bb994285f 100644 --- a/messagecomposer/attachmentpart.h +++ b/messagecomposer/attachmentpart.h @@ -1,58 +1,82 @@ /* Copyright (c) 2009 Constantin Berzan 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. */ #ifndef MESSAGECOMPOSER_ATTACHMENTPART_H #define MESSAGECOMPOSER_ATTACHMENTPART_H #include "messagepart.h" #include +#include + class KUrl; namespace MessageComposer { -/** setOverrideTransferEncoding for an AttachmentPart means setting the CTE for the sub-Content - representing this attachment */ class MESSAGECOMPOSER_EXPORT AttachmentPart : public MessagePart { Q_OBJECT public: typedef QList List; explicit AttachmentPart( QObject *parent = 0 ); virtual ~AttachmentPart(); - KUrl url() const; - void setUrl( const KUrl &url ); - - bool isDataLoaded() const; - bool loadData(); - - // TODO handle mime type; charset for textual types, etc. + /// the name= in Content-Type + QString name() const; + void setName( const QString &name ); + /// the filename= in Content-Disposition + QString fileName() const; + void setFileName( const QString &name ); + QString description() const; + void setDescription( const QString &description ); + // otherwise "attachment" + bool isInline() const; // Perhaps rename to autoDisplay, since the users of + // this class aren't supposed to know MIME? + void setInline( bool inl ); + // default true + bool isAutoEncoding() const; + void setAutoEncoding( bool enabled ); + // only if isAutoEncoding false + KMime::Headers::contentEncoding encoding() const; + void setEncoding( KMime::Headers::contentEncoding encoding ); + QByteArray mimeType() const; + void setMimeType( const QByteArray &mimeType ); + bool isCompressed() const; + void setCompressed( bool compressed ); + bool isEncrypted() const; + void setEncrypted( bool encrypted ); + bool isSigned() const; + void setSigned( bool sign ); + QByteArray data() const; + void setData( const QByteArray &data ); + qint64 size() const; + + // TODO outlook-compatible names... private: class Private; Private *const d; }; } // namespace MessageComposer -#endif // MESSAGECOMPOSER_INFOPART_H +#endif diff --git a/messagecomposer/behaviour.cpp b/messagecomposer/behaviour.cpp deleted file mode 100644 index 76167b6d5..000000000 --- a/messagecomposer/behaviour.cpp +++ /dev/null @@ -1,127 +0,0 @@ -/* - Copyright (c) 2009 Constantin Berzan - - 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. -*/ - -#include "behaviour.h" - -using namespace MessageComposer; - -Behaviour::Behaviour() - : d( new Private ) -{ - // Default behaviour for sending. - d->actions[ UseGui ] = true; - d->actions[ UseCrypto ] = true; - d->actions[ UseWrapping ] = true; - d->actions[ UseFallbackCharset ] = false; - d->actions[ WarnBadCharset ] = true; - d->actions[ WarnZeroRecipients ] = true; - d->actions[ CustomHeaders ] = false; - d->actions[ EightBitTransport ] = false; -} - -Behaviour::~Behaviour() -{ - // d is a QSharedDataPointer. -} - -bool Behaviour::isActionEnabled( Action action ) const -{ - Q_ASSERT( action >= 0 && action < LastAction ); - return d->actions[ action ]; -} - -void Behaviour::enableAction( Action action, bool enable ) -{ - Q_ASSERT( action >= 0 && action < LastAction ); - d->actions[ action ] = enable; -} - -void Behaviour::disableAction( Action action ) -{ - Q_ASSERT( action >= 0 && action < LastAction ); - d->actions[ action ] = false; -} - - - -//static -Behaviour Behaviour::behaviourForSending() -{ - static Behaviour beh; - // A default-constructed Behaviour has default sending behaviour. - return beh; -} - -//static -Behaviour Behaviour::behaviourForPrinting() -{ - static bool init = false; - static Behaviour beh; - if( !init ) { - beh.d->actions[ UseGui ] = true; - beh.d->actions[ UseCrypto ] = false; - beh.d->actions[ UseWrapping ] = true; - beh.d->actions[ UseFallbackCharset ] = false; - beh.d->actions[ WarnBadCharset ] = true; - beh.d->actions[ WarnZeroRecipients ] = false; - beh.d->actions[ CustomHeaders ] = false; - beh.d->actions[ EightBitTransport ] = false; - init = true; - } - return beh; -} - -//static -Behaviour Behaviour::behaviourForAutosaving() -{ - static bool init = false; - static Behaviour beh; - if( !init ) { - beh.d->actions[ UseGui ] = false; - beh.d->actions[ UseCrypto ] = false; - beh.d->actions[ UseWrapping ] = false; - beh.d->actions[ UseFallbackCharset ] = true; - beh.d->actions[ WarnBadCharset ] = false; - beh.d->actions[ WarnZeroRecipients ] = false; - beh.d->actions[ CustomHeaders ] = true; - beh.d->actions[ EightBitTransport ] = false; - init = true; - } - return beh; -} - -//static -Behaviour Behaviour::behaviourForSavingLocally() -{ - static bool init = false; - static Behaviour beh; - if( !init ) { - beh.d->actions[ UseGui ] = true; - beh.d->actions[ UseCrypto ] = false; - beh.d->actions[ UseWrapping ] = false; - beh.d->actions[ UseFallbackCharset ] = false; - beh.d->actions[ WarnBadCharset ] = true; - beh.d->actions[ WarnZeroRecipients ] = false; - beh.d->actions[ CustomHeaders ] = true; - beh.d->actions[ EightBitTransport ] = false; - init = true; - } - return beh; -} - diff --git a/messagecomposer/behaviour.h b/messagecomposer/behaviour.h deleted file mode 100644 index 2fc9c0ab6..000000000 --- a/messagecomposer/behaviour.h +++ /dev/null @@ -1,96 +0,0 @@ -/* - Copyright (c) 2009 Constantin Berzan - - 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. -*/ - -#ifndef MESSAGECOMPOSER_BEHAVIOUR_H -#define MESSAGECOMPOSER_BEHAVIOUR_H - -#include "messagecomposer_export.h" - -#include - -namespace MessageComposer { - -/** -*/ -class MESSAGECOMPOSER_EXPORT Behaviour -{ - public: - enum Action - { - UseGui, - UseCrypto, - UseWrapping, - UseFallbackCharset, - WarnBadCharset, - WarnZeroRecipients, - CustomHeaders, - EightBitTransport, - LastAction // TODO should this be made =100 for further expansion? - }; - - Behaviour(); - virtual ~Behaviour(); - - bool isActionEnabled( Action action ) const; - void enableAction( Action action, bool enable = true ); - void disableAction( Action action ); - - static Behaviour behaviourForSending(); - static Behaviour behaviourForPrinting(); - static Behaviour behaviourForAutosaving(); - static Behaviour behaviourForSavingLocally(); - - private: - class Private; - QSharedDataPointer d; -}; - -/* - FIXME - I can't figure out how else to make this work. If I put it in the cpp or in another - file like behaviour_p.h, I get 'incomplete type' errors. If I put it in behavior_p.h - and include it in the bottom, I need to install the _p anyway. - The problem seems to be that Behaviour needs Behaviour::Private (for QSharedDataPointer), - but Behaviour::Private needs Behaviour back (for Behaviour:LastAction). - -> I removed the latter dependency and the problem persists :-/ -*/ -/** - @internal -*/ -class Behaviour::Private : public QSharedData -{ - public: - Private() - { - } - - Private( const Private &other ) - : QSharedData( other ) - { - for( int i = 0; i < Behaviour::LastAction; i++ ) { - actions[i] = other.actions[i]; - } - } - - bool actions[ Behaviour::LastAction ]; -}; - -} - -#endif diff --git a/messagecomposer/composer.cpp b/messagecomposer/composer.cpp index ebf6ffa0b..64831cac0 100644 --- a/messagecomposer/composer.cpp +++ b/messagecomposer/composer.cpp @@ -1,374 +1,392 @@ /* Copyright (c) 2009 Constantin Berzan 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. */ #include "composer.h" #include "attachmentpart.h" #include "finalmessage_p.h" +#include "globalpart.h" #include "infopart.h" +#include "jobbase_p.h" #include "textpart.h" #include "maintextjob.h" #include "multipartjob.h" #include "skeletonmessagejob.h" #include #include using namespace MessageComposer; using namespace KMime; -class Composer::Private +class MessageComposer::ComposerPrivate : public JobBasePrivate { public: - Private( Composer *qq ) - : q( qq ) + ComposerPrivate( Composer *qq ) + : JobBasePrivate( qq ) , started( false ) , finished( false ) - , parentWidget( 0 ) - , infoPart( new InfoPart( q ) ) - , textPart( new TextPart( q ) ) + , globalPart( 0 ) + , infoPart( 0 ) + , textPart( 0 ) , skeletonMessage( 0 ) , contentBeforeCrypto( 0 ) #if 0 , pendingCryptoJobs( 0 ) #endif { } + void init(); void doStart(); // slot void composeStep1(); void splitAttachmentsIntoEarlyLate(); void skeletonJobFinished( KJob *job ); // slot void composeStep2(); void beforeCryptoJobFinished( KJob *job ); // slot void composeStep3(); FinalMessage *createFinalMessage( Content *content ); - Composer *q; - Behaviour behaviour; bool started; bool finished; FinalMessage::List messages; // Stuff that the application plays with. - QWidget *parentWidget; + GlobalPart *globalPart; InfoPart *infoPart; TextPart *textPart; AttachmentPart::List attachmentParts; // Stuff that we play with. AttachmentPart::List earlyAttachments; AttachmentPart::List lateAttachments; Message *skeletonMessage; Content *contentBeforeCrypto; // TODO crypto: for each resulting message, keep track of its recipient. // See keyresolver in kmail... // We need a structure to keep track of a recipient (list) as well as type // (to or cc or bcc), and createFinalMessage needs to honour it. #if 0 int pendingCryptoJobs; QList contentsAfterCrypto; #endif + + Q_DECLARE_PUBLIC( Composer ) }; -void Composer::Private::doStart() +void ComposerPrivate::init() +{ + Q_Q( Composer ); + globalPart = new GlobalPart( q ); + infoPart = new InfoPart( q ); + textPart = new TextPart( q ); + // FIXME: If I do these in ComposerPrivate's constructor, I get weird + // "Cannot create children for a parent that is in a different thread" + // errors. WTF? Something to do with construction order... I think q is + // not fully constructed by the time it is passed as a parent for these + // part QObjects. +} + +void ComposerPrivate::doStart() { Q_ASSERT( !started ); started = true; composeStep1(); } -void Composer::Private::composeStep1() +void ComposerPrivate::composeStep1() { + Q_Q( Composer ); + // Split the attachments into early and late. (see DESIGN) splitAttachmentsIntoEarlyLate(); // Create skeleton message (containing headers only; no content). SkeletonMessageJob *skeletonJob = new SkeletonMessageJob( infoPart, q ); - connect( skeletonJob, SIGNAL(finished(KJob*)), q, SLOT(skeletonJobFinished(KJob*)) ); + QObject::connect( skeletonJob, SIGNAL(finished(KJob*)), q, SLOT(skeletonJobFinished(KJob*)) ); q->addSubjob( skeletonJob ); skeletonJob->start(); } -void Composer::Private::splitAttachmentsIntoEarlyLate() +void ComposerPrivate::splitAttachmentsIntoEarlyLate() { // TODO earlyAttachments = attachmentParts; } -void Composer::Private::skeletonJobFinished( KJob *job ) +void ComposerPrivate::skeletonJobFinished( KJob *job ) { if( job->error() ) { return; // KCompositeJob takes care of the error. } Q_ASSERT( dynamic_cast( job ) ); SkeletonMessageJob *sjob = static_cast( job ); // SkeletonMessageJob is a special job creating a Message instead of a Content. Q_ASSERT( skeletonMessage == 0 ); skeletonMessage = sjob->message(); Q_ASSERT( skeletonMessage ); skeletonMessage->assemble(); kDebug() << "encoded content of skeleton" << skeletonMessage->encodedContent(); composeStep2(); } -void Composer::Private::composeStep2() +void ComposerPrivate::composeStep2() { - Job *beforeCryptoJob = 0; + Q_Q( Composer ); + + ContentJobBase *beforeCryptoJob = 0; // Create contentBeforeCrypto from the main text part and early attachments. if( earlyAttachments.isEmpty() ) { // We have no attachments. Use whatever content the textPart gives us. beforeCryptoJob = new MainTextJob( textPart, q ); } else { // We have attachments. Create a multipart/mixed content. // TODO Q_ASSERT( false ); #if 0 beforeCryptoJob = new MultipartJob( q ); beforeCryptoJob->setMultipartSubtype( "mixed" ); new MainTextJob( textPart, beforeCryptoJob ); foreach( AttachmentPart *part, earlyAttachments ) { new AttachmentJob( part, beforeCryptoJob ); } #endif } - connect( beforeCryptoJob, SIGNAL(finished(KJob*)), q, SLOT(beforeCryptoJobFinished(KJob*)) ); + QObject::connect( beforeCryptoJob, SIGNAL(finished(KJob*)), q, SLOT(beforeCryptoJobFinished(KJob*)) ); q->addSubjob( beforeCryptoJob ); beforeCryptoJob->start(); } -void Composer::Private::beforeCryptoJobFinished( KJob *job ) +void ComposerPrivate::beforeCryptoJobFinished( KJob *job ) { if( job->error() ) { return; // KCompositeJob takes care of the error. } - Q_ASSERT( dynamic_cast( job ) ); - Job *cjob = static_cast( job ); + Q_ASSERT( dynamic_cast( job ) ); + ContentJobBase *cjob = static_cast( job ); contentBeforeCrypto = cjob->content(); contentBeforeCrypto->assemble(); composeStep3(); } -void Composer::Private::composeStep3() +void ComposerPrivate::composeStep3() { + Q_Q( Composer ); + // (temporary until crypto) Compose final message. FinalMessage *msg = createFinalMessage( contentBeforeCrypto ); delete contentBeforeCrypto; contentBeforeCrypto = 0; messages << msg; kDebug() << "Finished composing the single lousy unencrypted message."; finished = true; q->emitResult(); #if 0 // The contentBeforeCrypto is done; now create contentsAfterCrypto. QList afterCryptoJobs = createAfterCryptoJobs(); pendingCryptoJobs = afterCryptoJobs.count(); foreach( const Job *cryptoJob, afterCryptoJobs ) { connect( cryptoJob, SIGNAL(finished(KJob*)), q, SLOT(afterCryptoJobFinished(KJob*)) ); cryptoJob->start(); } #endif } #if 0 -void Composer::Private::afterCryptoJobFinished( KJob *job ) +void ComposerPrivate::afterCryptoJobFinished( KJob *job ) { if( job->error() ) { return; // KCompositeJob takes care of the error. } Q_ASSERT( dynamic_cast( job ) ); Job *cryptoJob = static_cast( job ); contentsAfterCrypto << cryptoJob->content(); pendingCryptoJobs--; Q_ASSERT( pendingCryptoJobs >= 0 ); if( pendingCryptoJobs == 0 ) { // All contentsAfterCrypto are done; now add the late attachments. } } #endif -FinalMessage *Composer::Private::createFinalMessage( Content *content ) +FinalMessage *ComposerPrivate::createFinalMessage( Content *content ) { Q_ASSERT( skeletonMessage ); Message *message = new Message; // Merge the headers from skeletonMessage with the headers + content // of beforeCryptoJobFinished. FIXME HACK There should be a better way. QByteArray allData = skeletonMessage->head() + content->encodedContent(); message->setContent( allData ); + message->parse(); #if 0 // this was the second attempt QByteArray head = skeletonMessage->head() + content->head(); kDebug() << "head" << head; QByteArray body = content->body(); kDebug() << "body" << body; message->setHead( head ); message->setBody( body ); // With the above, for some reason the CTE thinks it has already encoded // the content, and so we get non-encoded content :-/ #endif #if 0 // this was the first attempt // Copy the content. FIXME There should be an easier way. content->assemble(); message->setContent( content->encodedContent() ); kDebug() << "encoded content" << content->encodedContent(); // Extract the headers from the skeletonMessage and copy them. // FIXME There should be an easier way. QByteArray head = skeletonMessage->head(); while( true ) { Headers::Base *header = skeletonMessage->nextHeader( head ); // Shouldn't this be static? if( !header ) { break; } kDebug() << "header from skeleton" << header->as7BitString(); message->setHeader( header ); header->setParent( message ); kDebug() << "created header @" << header; // The above SIGSEGVs for a reason I don't understand. // (when Akonadi tries to serialize the item) } #endif // Assemble the FinalMessage. #if 0 // part of 2nd attempt debugging //message->parse(); { kDebug() << "for the bloody content:"; Headers::ContentTransferEncoding *cte = content->contentTransferEncoding( false ); kDebug() << "CTE" << (cte ? cte->as7BitString() : "NULL"); if( cte ) { kDebug() << "decoded" << cte->decoded() << "needToEncode" << cte->needToEncode(); } } { kDebug() << "for the bloody message:"; Headers::ContentTransferEncoding *cte = message->contentTransferEncoding( false ); kDebug() << "CTE" << (cte ? cte->as7BitString() : "NULL"); if( cte ) { kDebug() << "decoded" << cte->decoded() << "needToEncode" << cte->needToEncode(); } } #endif - message->assemble(); + //message->assemble(); kDebug() << "encoded message after assembly" << message->encodedContent(); FinalMessage *finalMessage = new FinalMessage( message ); finalMessage->d->hasCustomHeaders = false; // TODO save those if not sending... finalMessage->d->transportId = infoPart->transportId(); // TODO will need to change this for crypto... finalMessage->d->from = infoPart->from(); finalMessage->d->to = infoPart->to(); finalMessage->d->cc = infoPart->cc(); finalMessage->d->bcc = infoPart->bcc(); return finalMessage; } Composer::Composer( QObject *parent ) - : KCompositeJob( parent ) - , d( new Private( this ) ) + : JobBase( *new ComposerPrivate( this ), parent ) { + Q_D( Composer ); + d->init(); } Composer::~Composer() { - delete d; -} - -Behaviour &Composer::behaviour() -{ - return d->behaviour; -} - -void Composer::setBehaviour( const Behaviour &beh ) -{ - d->behaviour = beh; -} - -QWidget *Composer::parentWidget() const -{ - return d->parentWidget; -} - -void Composer::setParentWidget( QWidget *widget ) -{ - d->parentWidget = widget; } FinalMessage::List Composer::messages() const { + Q_D( const Composer ); Q_ASSERT( d->finished ); Q_ASSERT( !error() ); return d->messages; } +GlobalPart *Composer::globalPart() +{ + Q_D( Composer ); + return d->globalPart; +} + InfoPart *Composer::infoPart() { + Q_D( Composer ); return d->infoPart; } TextPart *Composer::textPart() { + Q_D( Composer ); return d->textPart; } QList Composer::attachmentParts() { + Q_D( Composer ); return d->attachmentParts; } void Composer::addAttachmentPart( AttachmentPart *part ) { + Q_D( Composer ); Q_ASSERT( !d->started ); Q_ASSERT( !d->attachmentParts.contains( part ) ); d->attachmentParts.append( part ); + part->setParent( this ); } void Composer::removeAttachmentPart( AttachmentPart *part, bool del ) { + Q_D( Composer ); Q_ASSERT( !d->started ); if( d->attachmentParts.contains( part ) ) { d->attachmentParts.removeAll( part ); } else { kWarning() << "Unknown attachment part" << part; Q_ASSERT( false ); return; } if( del ) { delete part; + } else { + part->setParent( 0 ); } } void Composer::start() { QTimer::singleShot( 0, this, SLOT(doStart()) ); } #include "composer.moc" diff --git a/messagecomposer/composer.h b/messagecomposer/composer.h index 1d8d5dc19..758da76b5 100644 --- a/messagecomposer/composer.h +++ b/messagecomposer/composer.h @@ -1,83 +1,73 @@ /* Copyright (c) 2009 Constantin Berzan 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. */ #ifndef MESSAGECOMPOSER_COMPOSER_H #define MESSAGECOMPOSER_COMPOSER_H #include "attachmentpart.h" -#include "behaviour.h" #include "finalmessage.h" -#include "job.h" +#include "jobbase.h" #include "messagecomposer_export.h" #include #include -#include - namespace MessageComposer { +class ComposerPrivate; +class GlobalPart; class InfoPart; class TextPart; /** The message composer. */ -class MESSAGECOMPOSER_EXPORT Composer : public KCompositeJob +class MESSAGECOMPOSER_EXPORT Composer : public JobBase { Q_OBJECT public: - // TODO figure out how to share Job::Error (See PLAN). - explicit Composer( QObject *parent = 0 ); virtual ~Composer(); - Behaviour &behaviour(); - void setBehaviour( const Behaviour &beh ); - QWidget *parentWidget() const; // TODO make this part of Behaviour?? - void setParentWidget( QWidget *widget ); FinalMessage::List messages() const; + GlobalPart *globalPart(); InfoPart *infoPart(); - //void setInfoPart( InfoPart *part, bool delOldPart = true ); TextPart *textPart(); - //void setTextPart( TextPart *part, bool delOldPart = true ); - // TODO figure out how to make this extensible... - // and how to handle d->composer in MessagePart... AttachmentPart::List attachmentParts(); + // takes ownership void addAttachmentPart( AttachmentPart *part ); + // sets parent to 0 void removeAttachmentPart( AttachmentPart *part, bool del = true ); public Q_SLOTS: virtual void start(); private: - class Private; - friend class Private; - Private *const d; + Q_DECLARE_PRIVATE( Composer ) - Q_PRIVATE_SLOT( d, void doStart() ) - Q_PRIVATE_SLOT( d, void skeletonJobFinished(KJob*) ) - Q_PRIVATE_SLOT( d, void beforeCryptoJobFinished(KJob*) ) + Q_PRIVATE_SLOT( d_func(), void doStart() ) + Q_PRIVATE_SLOT( d_func(), void skeletonJobFinished(KJob*) ) + Q_PRIVATE_SLOT( d_func(), void beforeCryptoJobFinished(KJob*) ) }; } #endif diff --git a/messagecomposer/job.cpp b/messagecomposer/contentjobbase.cpp similarity index 54% rename from messagecomposer/job.cpp rename to messagecomposer/contentjobbase.cpp index 64e0e5425..9ce68e076 100644 --- a/messagecomposer/job.cpp +++ b/messagecomposer/contentjobbase.cpp @@ -1,125 +1,123 @@ /* Copyright (c) 2009 Constantin Berzan 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. */ -#include "job.h" -#include "job_p.h" - -#include "composer.h" +#include "contentjobbase.h" +#include "contentjobbase_p.h" #include #include +#include #include using namespace MessageComposer; using namespace KMime; -void JobPrivate::init( QObject *parent ) +void ContentJobBasePrivate::init( QObject *parent ) { - Composer *parentComposer = dynamic_cast( parent ); - if( parentComposer ) { - composer = parentComposer; - return; - } - - Job *parentJob = dynamic_cast( parent ); + Q_Q( ContentJobBase ); + ContentJobBase *parentJob = dynamic_cast( parent ); if( parentJob ) { - composer = parentJob->d_ptr->composer; - parentJob->addSubjob( q_ptr ); - return; + parentJob->appendSubjob( q ); } - - composer = 0; } -void JobPrivate::doNextSubjob() +void ContentJobBasePrivate::doNextSubjob() { - Q_Q( Job ); + Q_Q( ContentJobBase ); if( q->hasSubjobs() ) { q->subjobs().first()->start(); } else { kDebug() << "Calling process."; q->process(); } } -Job::Job( QObject *parent ) - : KCompositeJob( parent ) - , d_ptr( new JobPrivate( this ) ) +ContentJobBase::ContentJobBase( QObject *parent ) + : JobBase( *new ContentJobBasePrivate( this ), parent ) { - d_ptr->init( parent ); + Q_D( ContentJobBase ); + d->init( parent ); } -Job::Job( JobPrivate &dd, QObject *parent ) - : KCompositeJob( parent ) - , d_ptr( &dd ) +ContentJobBase::ContentJobBase( ContentJobBasePrivate &dd, QObject *parent ) + : JobBase( dd, parent ) { - d_ptr->init( parent ); + Q_D( ContentJobBase ); + d->init( parent ); } -Job::~Job() +ContentJobBase::~ContentJobBase() { - delete d_ptr; } -void Job::start() +void ContentJobBase::start() { QTimer::singleShot( 0, this, SLOT(doStart()) ); } -Content *Job::content() const +Content *ContentJobBase::content() const { - Q_D( const Job ); - //Q_ASSERT( !hasSubjobs() ); // Finished. // KCompositeJob::hasSubjobs is not const :-/ + Q_D( const ContentJobBase ); + //Q_ASSERT( !hasSubjobs() ); // Finished. // JobBase::hasSubjobs is not const :-/ TODO const_cast?? Q_ASSERT( d->resultContent ); // process() should do something. return d->resultContent; } -void Job::doStart() +bool ContentJobBase::appendSubjob( ContentJobBase *job ) { - Q_D( Job ); + job->setParent( this ); + return KCompositeJob::addSubjob( job ); +} + +bool ContentJobBase::addSubjob( KJob *job ) +{ + Q_UNUSED( job ); + kError() << "Use appendJob() instead."; + Q_ASSERT( false ); + return false; +} + +void ContentJobBase::doStart() +{ + Q_D( ContentJobBase ); Q_ASSERT( d->resultContent == 0 && d->subjobContents.isEmpty() ); // Not started. - Q_ASSERT( !error() ); // Jobs emitting an error in doStart should not call Job::doStart(). + Q_ASSERT( !error() ); // Jobs emitting an error in doStart should not call ContentJobBase::doStart(). d->doNextSubjob(); } -void Job::slotResult( KJob *job ) +void ContentJobBase::slotResult( KJob *job ) { - Q_D( Job ); + Q_D( ContentJobBase ); KCompositeJob::slotResult( job ); // Handles errors and removes subjob. kDebug() << "A subjob finished." << subjobs().count() << "more to go."; if( error() ) { return; } - Q_ASSERT( dynamic_cast( job ) ); - Job *cjob = static_cast( job ); + Q_ASSERT( dynamic_cast( job ) ); + ContentJobBase *cjob = static_cast( job ); d->subjobContents.append( cjob->content() ); d->doNextSubjob(); } -void Job::setComposer( Composer *composer ) -{ - d_ptr->composer = composer; -} - -#include "job.moc" +#include "contentjobbase.moc" diff --git a/messagecomposer/job.h b/messagecomposer/contentjobbase.h similarity index 69% rename from messagecomposer/job.h rename to messagecomposer/contentjobbase.h index 9470b75d1..ea12023b3 100644 --- a/messagecomposer/job.h +++ b/messagecomposer/contentjobbase.h @@ -1,102 +1,95 @@ /* Copyright (c) 2009 Constantin Berzan + Based on ideas by Stephen Kelly. 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. */ -#ifndef MESSAGECOMPOSER_JOB_H -#define MESSAGECOMPOSER_JOB_H +#ifndef MESSAGECOMPOSER_CONTENTJOBBASE_H +#define MESSAGECOMPOSER_CONTENTJOBBASE_H +#include "jobbase.h" #include "messagecomposer_export.h" -#include - -#include - namespace KMime { class Content; } namespace MessageComposer { -class Composer; -class JobPrivate; +class ContentJobBasePrivate; -class MESSAGECOMPOSER_EXPORT Job : public KCompositeJob +class MESSAGECOMPOSER_EXPORT ContentJobBase : public JobBase { Q_OBJECT public: - typedef QList List; - - enum Error - { - BugError = UserDefinedError + 1, - IncompleteError, - UserCancelledError, - UserError = UserDefinedError + 42 - }; - - explicit Job( QObject *parent = 0 ); - virtual ~Job(); + explicit ContentJobBase( QObject *parent = 0 ); + virtual ~ContentJobBase(); /** - Starts processing this Job asynchronously. + Starts processing this ContentJobBase asynchronously. This processes all children in order first, then calls process(). Emits finished() after all processing is done, and the content is reachable through content(). */ virtual void start(); /** - Get the resulting KMime::Content that the Job has generated. + Get the resulting KMime::Content that the ContentJobBase has generated. Jobs never delete their content. */ KMime::Content *content() const; + /** + This is meant to be used instead of KCompositeJob::addSubjob(), making + it possible to add subjobs from the outside. + Transfers ownership of the @p job to this object. + */ + bool appendSubjob( ContentJobBase *job ); + protected: - JobPrivate *const d_ptr; - Job( JobPrivate &dd, QObject *parent ); + ContentJobBase( ContentJobBasePrivate &dd, QObject *parent ); + + /** Use appendSubjob() instead. */ + virtual bool addSubjob( KJob *job ); protected Q_SLOTS: /** Reimplement to do additional stuff before processing children, such as adding more subjobs. Remember to call the base implementation. */ virtual void doStart(); /** This is called after all the children have been processed. (You must use their resulting contents, or delete them.) Reimplement in subclasses to process concrete content. Call emitResult() when finished. */ virtual void process() = 0; /* reimpl */ virtual void slotResult( KJob *job ); private: - friend class Composer; - void setComposer( Composer *composer ); - - Q_DECLARE_PRIVATE( Job ) + Q_DECLARE_PRIVATE( ContentJobBase ) }; } // namespace MessageComposer #endif diff --git a/messagecomposer/job_p.h b/messagecomposer/contentjobbase_p.h similarity index 83% rename from messagecomposer/job_p.h rename to messagecomposer/contentjobbase_p.h index 9d054dd89..7b4a44de3 100644 --- a/messagecomposer/job_p.h +++ b/messagecomposer/contentjobbase_p.h @@ -1,58 +1,50 @@ /* Copyright (c) 2009 Constantin Berzan 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. */ #ifndef MESSAGECOMPOSER_JOB_P_H #define MESSAGECOMPOSER_JOB_P_H -#include "job.h" +#include "contentjobbase.h" +#include "jobbase_p.h" #include namespace MessageComposer { -class Composer; - -class JobPrivate +class ContentJobBasePrivate : public JobBasePrivate { public: - JobPrivate( Job *qq ) - : composer( 0 ) + ContentJobBasePrivate( ContentJobBase *qq ) + : JobBasePrivate( qq ) , resultContent( 0 ) - , q_ptr( qq ) - { - } - - virtual ~JobPrivate() { } void init( QObject *parent ); void doNextSubjob(); - Composer *composer; KMime::Content *resultContent; KMime::Content::List subjobContents; - Job *q_ptr; - Q_DECLARE_PUBLIC( Job ) + Q_DECLARE_PUBLIC( ContentJobBase ) }; } #endif diff --git a/messagecomposer/finalmessage.h b/messagecomposer/finalmessage.h index c7274506f..9603a249e 100644 --- a/messagecomposer/finalmessage.h +++ b/messagecomposer/finalmessage.h @@ -1,62 +1,64 @@ /* Copyright (c) 2009 Constantin Berzan 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. */ #ifndef MESSAGECOMPOSER_FINALMESSAGE_H #define MESSAGECOMPOSER_FINALMESSAGE_H #include "messagecomposer_export.h" #include #include #include #include namespace MessageComposer { class Composer; +class ComposerPrivate; /** */ class MESSAGECOMPOSER_EXPORT FinalMessage { public: typedef QList List; KMime::Message::Ptr message() const; int transportId() const; bool hasCustomHeaders() const; QString from() const; QStringList to() const; QStringList cc() const; QStringList bcc() const; private: // Only used by our friend the Composer. friend class Composer; + friend class ComposerPrivate; // FIXME better ideas? explicit FinalMessage( KMime::Message *message = 0 ); virtual ~FinalMessage(); class Private; Private *const d; }; } #endif diff --git a/messagecomposer/globalpart.cpp b/messagecomposer/globalpart.cpp new file mode 100644 index 000000000..0527a7007 --- /dev/null +++ b/messagecomposer/globalpart.cpp @@ -0,0 +1,104 @@ +/* + Copyright (c) 2009 Constantin Berzan + + 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. +*/ + +#include "globalpart.h" + +using namespace MessageComposer; + +class GlobalPart::Private +{ + public: + bool guiEnabled; + QWidget *parentWidgetForGui; + bool fallbackCharsetEnabled; + QList charsets; + bool allow8Bit; +}; + +GlobalPart::GlobalPart( QObject *parent ) + : MessagePart( parent ) + , d( new Private ) +{ + d->guiEnabled = true; + d->parentWidgetForGui = 0; + d->fallbackCharsetEnabled = false; + d->allow8Bit = false; +} + +GlobalPart::~GlobalPart() +{ + delete d; +} + +bool GlobalPart::isGuiEnabled() const +{ + return d->guiEnabled; +} + +void GlobalPart::setGuiEnabled( bool enabled ) +{ + d->guiEnabled = enabled; +} + +QWidget* GlobalPart::parentWidgetForGui() const +{ + return d->parentWidgetForGui; +} + +void GlobalPart::setParentWidgetForGui( QWidget *widget ) +{ + d->parentWidgetForGui = widget; +} + +bool GlobalPart::isFallbackCharsetEnabled() const +{ + return d->fallbackCharsetEnabled; +} + +void GlobalPart::setFallbackCharsetEnabled( bool enabled ) +{ + d->fallbackCharsetEnabled = enabled; +} + +QList GlobalPart::charsets( bool forceFallback ) const +{ + QList ret = d->charsets; + if( d->fallbackCharsetEnabled || forceFallback ) { + ret << "us-ascii"; + ret << "utf-8"; + } + return ret; +} + +void GlobalPart::setCharsets( const QList &charsets ) +{ + d->charsets = charsets; +} + +bool GlobalPart::is8BitAllowed() const +{ + return d->allow8Bit; +} + +void GlobalPart::set8BitAllowed( bool allowed ) +{ + d->allow8Bit = allowed; +} + +#include "globalpart.moc" diff --git a/messagecomposer/attachmentpart.h b/messagecomposer/globalpart.h similarity index 58% copy from messagecomposer/attachmentpart.h copy to messagecomposer/globalpart.h index 6a15c8528..b4300c983 100644 --- a/messagecomposer/attachmentpart.h +++ b/messagecomposer/globalpart.h @@ -1,58 +1,59 @@ /* Copyright (c) 2009 Constantin Berzan 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. */ -#ifndef MESSAGECOMPOSER_ATTACHMENTPART_H -#define MESSAGECOMPOSER_ATTACHMENTPART_H +#ifndef MESSAGECOMPOSER_GLOBALPART_H +#define MESSAGECOMPOSER_GLOBALPART_H #include "messagepart.h" +#include #include -class KUrl; - namespace MessageComposer { -/** setOverrideTransferEncoding for an AttachmentPart means setting the CTE for the sub-Content - representing this attachment */ -class MESSAGECOMPOSER_EXPORT AttachmentPart : public MessagePart +class MESSAGECOMPOSER_EXPORT GlobalPart : public MessagePart { Q_OBJECT public: - typedef QList List; + explicit GlobalPart( QObject *parent = 0 ); + virtual ~GlobalPart(); - explicit AttachmentPart( QObject *parent = 0 ); - virtual ~AttachmentPart(); + // default true + bool isGuiEnabled() const; + void setGuiEnabled( bool enabled ); + QWidget* parentWidgetForGui() const; + void setParentWidgetForGui( QWidget *widget ); - KUrl url() const; - void setUrl( const KUrl &url ); - - bool isDataLoaded() const; - bool loadData(); + bool isFallbackCharsetEnabled() const; + void setFallbackCharsetEnabled( bool enabled ); + QList charsets( bool forceFallback = false ) const; + void setCharsets( const QList &charsets ); - // TODO handle mime type; charset for textual types, etc. + bool is8BitAllowed() const; + void set8BitAllowed( bool allowed ); private: class Private; Private *const d; }; } // namespace MessageComposer -#endif // MESSAGECOMPOSER_INFOPART_H +#endif diff --git a/messagecomposer/infopart.h b/messagecomposer/infopart.h index 90beadc9b..bb4ccc081 100644 --- a/messagecomposer/infopart.h +++ b/messagecomposer/infopart.h @@ -1,63 +1,62 @@ /* Copyright (c) 2009 Constantin Berzan 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. */ #ifndef MESSAGECOMPOSER_INFOPART_H #define MESSAGECOMPOSER_INFOPART_H #include "messagepart.h" #include #include #include namespace MessageComposer { -/** setOverrideTransferEncoding for an InfoPart has no effect */ class MESSAGECOMPOSER_EXPORT InfoPart : public MessagePart { Q_OBJECT public: explicit InfoPart( QObject *parent = 0 ); virtual ~InfoPart(); QString from() const; void setFrom( const QString &from ); QStringList to() const; void setTo( const QStringList &to ); QStringList cc() const; void setCc( const QStringList &cc ); QStringList bcc() const; void setBcc( const QStringList &bcc ); QString subject() const; void setSubject( const QString &subject ); int transportId() const; void setTransportId( int tid ); private: class Private; Private *const d; }; } // namespace MessageComposer #endif // MESSAGECOMPOSER_INFOPART_H diff --git a/messagecomposer/attachmentpart.cpp b/messagecomposer/jobbase.cpp similarity index 58% copy from messagecomposer/attachmentpart.cpp copy to messagecomposer/jobbase.cpp index 6110b6fc6..5e518def9 100644 --- a/messagecomposer/attachmentpart.cpp +++ b/messagecomposer/jobbase.cpp @@ -1,68 +1,59 @@ /* Copyright (c) 2009 Constantin Berzan 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. */ -#include "attachmentpart.h" +#include "jobbase.h" -#include +#include "composer.h" +#include "jobbase_p.h" -using namespace MessageComposer; - -class MessageComposer::AttachmentPart::Private -{ - public: - KUrl url; - bool dataLoaded; - QByteArray data; -}; +#include -AttachmentPart::AttachmentPart( QObject *parent ) - : MessagePart( parent ) - , d( new Private ) -{ - d->dataLoaded = false; -} - -AttachmentPart::~AttachmentPart() -{ - delete d; -} +using namespace MessageComposer; -KUrl AttachmentPart::url() const +JobBase::JobBase( QObject *parent ) + : KCompositeJob( parent ) + , d_ptr( new JobBasePrivate( this ) ) { - return d->url; } -void AttachmentPart::setUrl( const KUrl &url ) +JobBase::JobBase( JobBasePrivate &dd, QObject *parent ) + : KCompositeJob( parent ) + , d_ptr( &dd ) { - d->url = url; - d->dataLoaded = false; } -bool AttachmentPart::isDataLoaded() const +JobBase::~JobBase() { - return d->dataLoaded; + delete d_ptr; } -bool AttachmentPart::loadData() +GlobalPart *JobBase::globalPart() { - // TODO - return false; + for( QObject *obj = this; obj != 0; obj = obj->parent() ) { + Composer *composer = qobject_cast( obj ); + if( composer ) { + return composer->globalPart(); + } + } + + kFatal() << "Job is not part of a Composer."; + return 0; } -#include "attachmentpart.moc" +#include "jobbase.moc" diff --git a/messagecomposer/skeletonmessagejob.h b/messagecomposer/jobbase.h similarity index 55% copy from messagecomposer/skeletonmessagejob.h copy to messagecomposer/jobbase.h index b1b8eddd6..00eff8fa3 100644 --- a/messagecomposer/skeletonmessagejob.h +++ b/messagecomposer/jobbase.h @@ -1,63 +1,69 @@ /* Copyright (c) 2009 Constantin Berzan - Based on ideas by Stephen Kelly. 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. */ -#ifndef MESSAGECOMPOSER_SKELETONMESSAGEJOB_H -#define MESSAGECOMPOSER_SKELETONMESSAGEJOB_H +#ifndef MESSAGECOMPOSER_JOBBASE_H +#define MESSAGECOMPOSER_JOBBASE_H -#include "job.h" #include "messagecomposer_export.h" -namespace KMime { - class Message; -} +#include + +#include namespace MessageComposer { -class SkeletonMessageJobPrivate; -class InfoPart; +class GlobalPart; +class JobBasePrivate; /** - A message containing only the headers... + A dummy abstract class defining some errors pertaining to the Composer. + It is meant to be subclassed. */ -class MESSAGECOMPOSER_EXPORT SkeletonMessageJob : public Job +class MESSAGECOMPOSER_EXPORT JobBase : public KCompositeJob { Q_OBJECT public: - explicit SkeletonMessageJob( InfoPart *infoPart = 0, QObject *parent = 0 ); - virtual ~SkeletonMessageJob(); + typedef QList List; + + enum Error + { + BugError = UserDefinedError + 1, + IncompleteError, + UserCancelledError, + UserError = UserDefinedError + 42 + }; - InfoPart *infoPart() const; - void setInfoPart( InfoPart *part ); + explicit JobBase( QObject *parent = 0 ); + virtual ~JobBase(); - KMime::Message *message() const; - // TODO I think there is a way in C++ to make content() private, even if it's public - // in the base class. + // asserts if no Composer parent + GlobalPart *globalPart(); - protected Q_SLOTS: - virtual void process(); + protected: + JobBasePrivate *const d_ptr; + JobBase( JobBasePrivate &dd, QObject *parent ); private: - Q_DECLARE_PRIVATE( SkeletonMessageJob ) + Q_DECLARE_PRIVATE( JobBase ) }; } // namespace MessageComposer #endif diff --git a/messagecomposer/behaviour_p.h b/messagecomposer/jobbase_p.h similarity index 74% copy from messagecomposer/behaviour_p.h copy to messagecomposer/jobbase_p.h index 34dcf87af..f84a8f234 100644 --- a/messagecomposer/behaviour_p.h +++ b/messagecomposer/jobbase_p.h @@ -1,33 +1,45 @@ /* Copyright (c) 2009 Constantin Berzan 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. */ -#include +#ifndef MESSAGECOMPOSER_JOBBASE_P_H +#define MESSAGECOMPOSER_JOBBASE_P_H -#ifndef MESSAGECOMPOSER_BEHAVIOUR_P_H -#define MESSAGECOMPOSER_BEHAVIOUR_P_H +#include "jobbase.h" namespace MessageComposer { -/** - @internal -*/ +class JobBasePrivate +{ + public: + JobBasePrivate( JobBase *qq ) + : q_ptr( qq ) + { + } + + virtual ~JobBasePrivate() + { + } + + JobBase *q_ptr; + Q_DECLARE_PUBLIC( JobBase ) +}; } #endif diff --git a/messagecomposer/maintextjob.cpp b/messagecomposer/maintextjob.cpp index 681a872d1..81de0b16b 100644 --- a/messagecomposer/maintextjob.cpp +++ b/messagecomposer/maintextjob.cpp @@ -1,283 +1,296 @@ /* Copyright (c) 2009 Constantin Berzan 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. */ #include "maintextjob.h" -#include "composer.h" -#include "contentjob.h" -#include "job_p.h" +#include "contentjobbase_p.h" +#include "globalpart.h" +#include "multipartjob.h" +#include "singlepartjob.h" #include "textpart.h" +#include "util.h" #include #include #include #include #include #include #include -#include + +#include using namespace MessageComposer; using namespace KMime; -class MessageComposer::MainTextJobPrivate : public JobPrivate +class MessageComposer::MainTextJobPrivate : public ContentJobBasePrivate { public: MainTextJobPrivate( MainTextJob *qq ) - : JobPrivate( qq ) + : ContentJobBasePrivate( qq ) , textPart( 0 ) { } bool chooseSourcePlainText(); bool chooseCharsetAndEncode(); bool chooseCharset(); - void encodeTexts(); + bool encodeTexts(); + SinglepartJob *createPlainTextJob(); + SinglepartJob *createHtmlJob(); + SinglepartJob *createImageJob( const QSharedPointer &image ); TextPart *textPart; - QList charsets; QByteArray chosenCharset; QString sourcePlainText; QByteArray encodedPlainText; QByteArray encodedHtml; - // TODO related images - Q_DECLARE_PUBLIC( MainTextJob ) }; bool MainTextJobPrivate::chooseSourcePlainText() { Q_Q( MainTextJob ); - Q_ASSERT( composer ); Q_ASSERT( textPart ); - if( composer->behaviour().isActionEnabled( Behaviour::UseWrapping ) ) { + if( textPart->isWordWrappingEnabled() ) { sourcePlainText = textPart->wrappedPlainText(); if( sourcePlainText.isEmpty() && !textPart->cleanPlainText().isEmpty() ) { - q->setError( Job::BugError ); + q->setError( JobBase::BugError ); q->setErrorText( i18n( "Asked to use word wrapping, but given no wrapped plain text." ) ); return false; } } else { sourcePlainText = textPart->cleanPlainText(); if( sourcePlainText.isEmpty() && !textPart->wrappedPlainText().isEmpty() ) { - q->setError( Job::BugError ); + q->setError( JobBase::BugError ); q->setErrorText( i18n( "Asked not to use word wrapping, but given no clean plain text." ) ); return false; } } return true; } bool MainTextJobPrivate::chooseCharsetAndEncode() { Q_Q( MainTextJob ); - Q_ASSERT( composer ); - const Behaviour &beh = composer->behaviour(); - Q_ASSERT( textPart ); - charsets = textPart->charsets(); - foreach( const QByteArray &name, textPart->charsets() ) { - charsets << name.toLower(); - } - if( beh.isActionEnabled( Behaviour::UseFallbackCharset ) ) { - charsets << "utf-8"; - // TODO somehow save the chosen charset in a custom header if behaviour allows it... - } + const QList charsets = q->globalPart()->charsets(); if( charsets.isEmpty() ) { - q->setError( Job::BugError ); - q->setErrorText( i18n( "No charsets were available for encoding," - " and the fallback charset was disabled." ) ); + q->setError( JobBase::BugError ); + q->setErrorText( i18n( "No charsets were available for encoding." ) ); return false; } - if( chooseCharset() ) { - // Good, one of the charsets can encode the data without loss. - encodeTexts(); - return true; + Q_ASSERT( textPart ); + QString toTry = sourcePlainText; + if( textPart->isHtmlUsed() ) { + toTry = textPart->cleanHtml(); + } + chosenCharset = selectCharset( charsets, toTry ); + if( !chosenCharset.isEmpty() ) { + // Good, found a charset that encodes the data without loss. + return encodeTexts(); } else { // No good charset was found. - if( beh.isActionEnabled( Behaviour::UseGui ) && - beh.isActionEnabled( Behaviour::WarnBadCharset ) ) { + if( q->globalPart()->isGuiEnabled() && textPart->warnBadCharset() ) { // Warn the user and give them a chance to go back. int result = KMessageBox::warningYesNo( - composer->parentWidget(), + q->globalPart()->parentWidgetForGui(), i18n( "Encoding the message with %1 will lose some characters.\n" "Do you want to continue?", QString::fromLatin1( charsets.first() ) ), i18n( "Some Characters Will Be Lost" ), KGuiItem( i18n("Lose Characters") ), KGuiItem( i18n("Change Encoding") ) ); if( result == KMessageBox::No ) { - q->setError( Job::UserCancelledError ); + q->setError( JobBase::UserCancelledError ); q->setErrorText( i18n( "User decided to change the encoding." ) ); return false; } else { chosenCharset = charsets.first(); - encodeTexts(); - return true; + return encodeTexts(); } - } else if( beh.isActionEnabled( Behaviour::WarnBadCharset ) ) { + } else if( textPart->warnBadCharset() ) { // Should warn user but no Gui available. - kDebug() << "WarnBadCharset but not UseGui."; - q->setError( Job::UserError ); + kDebug() << "warnBadCharset but Gui is disabled."; + q->setError( JobBase::UserError ); q->setErrorText( i18n( "The selected encoding (%1) cannot fully encode the message.", QString::fromLatin1( charsets.first() ) ) ); return false; } else { // OK to go ahead with a bad charset. chosenCharset = charsets.first(); - encodeTexts(); - return true; + return encodeTexts(); // FIXME: This is based on the assumption that QTextCodec will replace // unknown characters with '?' or some other meaningful thing. The code in // QTextCodec indeed uses '?', but this behaviour is not documented. } } // Should not reach here. Q_ASSERT( false ); return false; } -bool MainTextJobPrivate::chooseCharset() -{ - Q_ASSERT( !charsets.isEmpty() ); - Q_ASSERT( textPart ); - QString toTry = sourcePlainText; - if( textPart->isHtmlUsed() ) { - toTry = textPart->cleanHtml(); - } - foreach( const QByteArray &name, charsets ) { - // We use KCharsets::codecForName() instead of QTextCodec::codecForName() here, because - // the former knows us-ascii is latin1. - QTextCodec *codec = KGlobal::charsets()->codecForName( QString::fromLatin1( name ) ); - if( !codec ) { - kWarning() << "Could not get text codec for charset" << name; - continue; - } - if( codec->canEncode( toTry ) ) { - // Special check for us-ascii (needed because us-ascii is not exactly latin1). - if( name == "us-ascii" && !isUsAscii( toTry ) ) { - continue; - } - kDebug() << "Chosen charset" << name; - chosenCharset = name; - return true; - } - } - kDebug() << "No appropriate charset found."; - return false; -} - -void MainTextJobPrivate::encodeTexts() +bool MainTextJobPrivate::encodeTexts() { Q_Q( MainTextJob ); QTextCodec *codec = KGlobal::charsets()->codecForName( QString::fromLatin1( chosenCharset ) ); if( !codec ) { kError() << "Could not get text codec for charset" << chosenCharset; - q->setError( Job::BugError ); + q->setError( JobBase::BugError ); q->setErrorText( i18n( "Could not get text codec for charset \"%1\".", QString::fromLatin1( chosenCharset ) ) ); - return; + return false; } encodedPlainText = codec->fromUnicode( sourcePlainText ); encodedHtml = codec->fromUnicode( textPart->cleanHtml() ); kDebug() << "Done."; + return true; } +SinglepartJob *MainTextJobPrivate::createPlainTextJob() +{ + SinglepartJob *cjob = new SinglepartJob; // No parent. + cjob->contentType()->setMimeType( "text/plain" ); + cjob->contentType()->setCharset( chosenCharset ); + cjob->setData( encodedPlainText ); + // TODO standard recommends Content-ID. + return cjob; +} +SinglepartJob *MainTextJobPrivate::createHtmlJob() +{ + SinglepartJob *cjob = new SinglepartJob; // No parent. + cjob->contentType()->setMimeType( "text/html" ); + cjob->contentType()->setCharset( chosenCharset ); + QByteArray data = KPIMTextEdit::TextEdit::imageNamesToContentIds( encodedHtml, + textPart->embeddedImages() ); + cjob->setData( data ); + // TODO standard recommends Content-ID. + return cjob; +} + +SinglepartJob *MainTextJobPrivate::createImageJob( const QSharedPointer &image ) +{ + Q_Q( MainTextJob ); + + // The image is a PNG encoded with base64. + SinglepartJob *cjob = new SinglepartJob; // No parent. + cjob->contentType()->setMimeType( "image/png" ); + const QByteArray charset = selectCharset( q->globalPart()->charsets( true ), image->imageName ); + Q_ASSERT( !charset.isEmpty() ); + cjob->contentType()->setName( image->imageName, charset ); + cjob->contentTransferEncoding()->setEncoding( Headers::CEbase64 ); + cjob->contentTransferEncoding()->setDecoded( false ); // It is already encoded. + cjob->contentID()->setIdentifier( image->contentID.toLatin1() ); + kDebug() << "cid" << cjob->contentID()->identifier(); + cjob->setData( image->image ); + return cjob; +} MainTextJob::MainTextJob( TextPart *textPart, QObject *parent ) - : Job( *new MainTextJobPrivate( this ), parent ) + : ContentJobBase( *new MainTextJobPrivate( this ), parent ) { Q_D( MainTextJob ); d->textPart = textPart; } MainTextJob::~MainTextJob() { } TextPart *MainTextJob::textPart() const { Q_D( const MainTextJob ); return d->textPart; } void MainTextJob::setTextPart( TextPart *part ) { Q_D( MainTextJob ); d->textPart = part; } void MainTextJob::doStart() { Q_D( MainTextJob ); Q_ASSERT( d->textPart ); - Q_ASSERT( d->composer ); // Word wrapping. if( !d->chooseSourcePlainText() ) { // chooseSourcePlainText has set an error. Q_ASSERT( error() ); emitResult(); return; } // Charset. if( !d->chooseCharsetAndEncode() ) { // chooseCharsetAndEncode has set an error. Q_ASSERT( error() ); emitResult(); return; } // Assemble the Content. + SinglepartJob *plainJob = d->createPlainTextJob(); if( d->encodedHtml.isEmpty() ) { kDebug() << "Making text/plain"; // Content is text/plain. - ContentJob *cjob = new ContentJob( this ); - cjob->contentType()->setMimeType( "text/plain" ); - cjob->contentType()->setCharset( d->chosenCharset ); - cjob->setData( d->encodedPlainText ); - if( !d->textPart->isAutoTransferEncoding() ) { - cjob->contentTransferEncoding()->setEncoding( d->textPart->overrideTransferEncoding() ); - } + appendSubjob( plainJob ); } else { - // TODO Handle multipart/alternative and multipart/related. - Q_ASSERT( false ); + MultipartJob *alternativeJob = new MultipartJob; + alternativeJob->setMultipartSubtype( "alternative" ); + alternativeJob->appendSubjob( plainJob ); // text/plain first. + alternativeJob->appendSubjob( d->createHtmlJob() ); // text/html second. + if( !d->textPart->hasEmbeddedImages() ) { + kDebug() << "Have no images. Making multipart/alternative."; + // Content is multipart/alternative. + appendSubjob( alternativeJob ); + } else { + kDebug() << "Have related images. Making multipart/related."; + // Content is multipart/related with a multipart/alternative sub-Content. + MultipartJob *multipartJob = new MultipartJob; + multipartJob->setMultipartSubtype( "related" ); + multipartJob->appendSubjob( alternativeJob ); + foreach( const QSharedPointer &image, d->textPart->embeddedImages() ) { + multipartJob->appendSubjob( d->createImageJob( image ) ); + } + appendSubjob( multipartJob ); + } } - Job::doStart(); + ContentJobBase::doStart(); } void MainTextJob::process() { Q_D( MainTextJob ); // The content has been created by our subjob. Q_ASSERT( d->subjobContents.count() == 1 ); d->resultContent = d->subjobContents.first(); emitResult(); } #include "maintextjob.moc" diff --git a/messagecomposer/maintextjob.h b/messagecomposer/maintextjob.h index 3b2b45cb7..9bc624751 100644 --- a/messagecomposer/maintextjob.h +++ b/messagecomposer/maintextjob.h @@ -1,53 +1,52 @@ /* Copyright (c) 2009 Constantin Berzan - Based on ideas by Stephen Kelly. 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. */ #ifndef MESSAGECOMPOSER_MAINTEXTJOB_H #define MESSAGECOMPOSER_MAINTEXTJOB_H -#include "job.h" +#include "contentjobbase.h" #include "messagecomposer_export.h" namespace MessageComposer { class MainTextJobPrivate; class TextPart; -class MESSAGECOMPOSER_EXPORT MainTextJob : public Job +class MESSAGECOMPOSER_EXPORT MainTextJob : public ContentJobBase { Q_OBJECT public: explicit MainTextJob( TextPart *textPart = 0, QObject *parent = 0 ); virtual ~MainTextJob(); TextPart *textPart() const; void setTextPart( TextPart *part ); protected Q_SLOTS: virtual void doStart(); virtual void process(); private: Q_DECLARE_PRIVATE( MainTextJob ) }; } // namespace MessageComposer #endif diff --git a/messagecomposer/messagepart.cpp b/messagecomposer/messagepart.cpp index e0699d3e9..d0bca5a94 100644 --- a/messagecomposer/messagepart.cpp +++ b/messagecomposer/messagepart.cpp @@ -1,72 +1,47 @@ /* Copyright (c) 2009 Constantin Berzan 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. */ #include "messagepart.h" #include -using namespace KMime; using namespace MessageComposer; class MessagePart::Private { public: Private() - : autoCTE( true ) { } - - bool autoCTE; - Headers::contentEncoding cte; }; MessagePart::MessagePart( QObject *parent ) : QObject( parent ) , d( new Private ) { } MessagePart::~MessagePart() { delete d; } -bool MessagePart::isAutoTransferEncoding() const -{ - return d->autoCTE; -} - -KMime::Headers::contentEncoding MessagePart::overrideTransferEncoding() const -{ - if( d->autoCTE ) { - kWarning() << "Called when CTE is auto."; - return Headers::CEbinary; - } - return d->cte; -} - -void MessagePart::setOverrideTransferEncoding( KMime::Headers::contentEncoding cte ) -{ - d->autoCTE = false; - d->cte = cte; -} - #include "messagepart.moc" diff --git a/messagecomposer/messagepart.h b/messagecomposer/messagepart.h index 4ad60f2bf..a2ace0bd4 100644 --- a/messagecomposer/messagepart.h +++ b/messagecomposer/messagepart.h @@ -1,55 +1,50 @@ /* Copyright (c) 2009 Constantin Berzan 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. */ #ifndef MESSAGECOMPOSER_MESSAGEPART_H #define MESSAGECOMPOSER_MESSAGEPART_H -#include "behaviour.h" #include "messagecomposer_export.h" #include #include namespace MessageComposer { class MessagePartPrivate; /** */ class MESSAGECOMPOSER_EXPORT MessagePart : public QObject { Q_OBJECT public: MessagePart( QObject *parent = 0 ); virtual ~MessagePart(); - bool isAutoTransferEncoding() const; - KMime::Headers::contentEncoding overrideTransferEncoding() const; - void setOverrideTransferEncoding( KMime::Headers::contentEncoding cte ); - private: class Private; Private *const d; }; } #endif diff --git a/messagecomposer/multipartjob.cpp b/messagecomposer/multipartjob.cpp index ebc98bf38..8f75e35e6 100644 --- a/messagecomposer/multipartjob.cpp +++ b/messagecomposer/multipartjob.cpp @@ -1,83 +1,84 @@ /* Copyright (c) 2009 Constantin Berzan 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. */ #include "multipartjob.h" -#include "job_p.h" +#include "contentjobbase_p.h" #include #include using namespace MessageComposer; using namespace KMime; -class MessageComposer::MultipartJobPrivate : public JobPrivate +class MessageComposer::MultipartJobPrivate : public ContentJobBasePrivate { public: MultipartJobPrivate( MultipartJob *qq ) - : JobPrivate( qq ) + : ContentJobBasePrivate( qq ) { } QByteArray subtype; }; MultipartJob::MultipartJob( QObject *parent ) - : Job( *new MultipartJobPrivate( this ), parent ) + : ContentJobBase( *new MultipartJobPrivate( this ), parent ) { } MultipartJob::~MultipartJob() { } QByteArray MultipartJob::multipartSubtype() const { Q_D( const MultipartJob ); return d->subtype; } void MultipartJob::setMultipartSubtype( const QByteArray &subtype ) { Q_D( MultipartJob ); d->subtype = subtype; } void MultipartJob::process() { Q_D( MultipartJob ); Q_ASSERT( d->resultContent == 0 ); // Not processed before. Q_ASSERT( !d->subtype.isEmpty() ); d->resultContent = new Content; d->resultContent->contentType( true )->setMimeType( "multipart/" + d->subtype ); d->resultContent->contentType()->setBoundary( KMime::multiPartBoundary() ); d->resultContent->contentTransferEncoding()->setEncoding( Headers::CE7Bit ); foreach( Content *c, d->subjobContents ) { d->resultContent->addContent( c ); if( c->contentTransferEncoding()->encoding() == Headers::CE8Bit ) { d->resultContent->contentTransferEncoding()->setEncoding( Headers::CE8Bit ); + break; } } kDebug() << "Created" << d->resultContent->contentType()->name() << "content with" << d->resultContent->contents().count() << "subjobContents."; emitResult(); } #include "multipartjob.moc" diff --git a/messagecomposer/multipartjob.h b/messagecomposer/multipartjob.h index 76821b060..f08af842d 100644 --- a/messagecomposer/multipartjob.h +++ b/messagecomposer/multipartjob.h @@ -1,52 +1,52 @@ /* Copyright (c) 2009 Constantin Berzan 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. */ #ifndef MESSAGECOMPOSER_MULTIPARTJOB_H #define MESSAGECOMPOSER_MULTIPARTJOB_H -#include "job.h" +#include "contentjobbase.h" #include "messagecomposer_export.h" namespace MessageComposer { class MultipartJobPrivate; /** */ -class MESSAGECOMPOSER_EXPORT MultipartJob : public Job +class MESSAGECOMPOSER_EXPORT MultipartJob : public ContentJobBase { Q_OBJECT public: MultipartJob( QObject *parent = 0 ); virtual ~MultipartJob(); QByteArray multipartSubtype() const; void setMultipartSubtype( const QByteArray &subtype ); protected Q_SLOTS: virtual void process(); private: Q_DECLARE_PRIVATE( MultipartJob ) }; } #endif diff --git a/messagecomposer/contentjob.cpp b/messagecomposer/singlepartjob.cpp similarity index 67% rename from messagecomposer/contentjob.cpp rename to messagecomposer/singlepartjob.cpp index 36af8fdb2..f115968f6 100644 --- a/messagecomposer/contentjob.cpp +++ b/messagecomposer/singlepartjob.cpp @@ -1,209 +1,198 @@ /* Copyright (c) 2009 Constantin Berzan 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. */ -#include "contentjob.h" +#include "singlepartjob.h" #include "composer.h" -#include "job_p.h" +#include "contentjobbase_p.h" +#include "globalpart.h" #include "util.h" #include #include -#include #include #include using namespace MessageComposer; using namespace KMime; -class MessageComposer::ContentJobPrivate : public JobPrivate +class MessageComposer::SinglepartJobPrivate : public ContentJobBasePrivate { public: - ContentJobPrivate( ContentJob *qq ) - : JobPrivate( qq ) + SinglepartJobPrivate( SinglepartJob *qq ) + : ContentJobBasePrivate( qq ) , contentDisposition( 0 ) + , contentID( 0 ) , contentTransferEncoding( 0 ) , contentType( 0 ) { } bool chooseCTE(); QByteArray data; Headers::ContentDisposition *contentDisposition; + Headers::ContentID *contentID; Headers::ContentTransferEncoding *contentTransferEncoding; Headers::ContentType *contentType; - Q_DECLARE_PUBLIC( ContentJob ) + Q_DECLARE_PUBLIC( SinglepartJob ) }; -bool ContentJobPrivate::chooseCTE() +bool SinglepartJobPrivate::chooseCTE() { - // Based on KMail code by: - // Copyright 2009 Thomas McGuire - - Q_Q( ContentJob ); - Q_ASSERT( composer ); - QList allowed; - CharFreq cf( data ); - - switch ( cf.type() ) { - case CharFreq::SevenBitText: - allowed << Headers::CE7Bit; - case CharFreq::EightBitText: - if ( composer->behaviour().isActionEnabled( Behaviour::EightBitTransport ) ) - allowed << Headers::CE8Bit; - case CharFreq::SevenBitData: - if ( cf.printableRatio() > 5.0/6.0 ) { - // let n the length of data and p the number of printable chars. - // Then base64 \approx 4n/3; qp \approx p + 3(n-p) - // => qp < base64 iff p > 5n/6. - allowed << Headers::CEquPr; - allowed << Headers::CEbase64; - } else { - allowed << Headers::CEbase64; - allowed << Headers::CEquPr; - } - break; - case CharFreq::EightBitData: - allowed << Headers::CEbase64; - break; - case CharFreq::None: - default: - Q_ASSERT( false ); + Q_Q( SinglepartJob ); + + QList allowed = encodingsForData( data ); + + if( !q->globalPart()->is8BitAllowed() ) { + allowed.removeAll( Headers::CE8Bit ); } #if 0 //TODO signing // In the following cases only QP and Base64 are allowed: // - the buffer will be OpenPGP/MIME signed and it contains trailing // whitespace (cf. RFC 3156) // - a line starts with "From " if ( ( willBeSigned && cf.hasTrailingWhitespace() ) || cf.hasLeadingFrom() ) { ret.removeAll( DwMime::kCte8bit ); ret.removeAll( DwMime::kCte7bit ); } #endif if( contentTransferEncoding ) { // Specific CTE set. Check that our data fits in it. if( !allowed.contains( contentTransferEncoding->encoding() ) ) { - q->setError( Job::BugError ); + q->setError( JobBase::BugError ); q->setErrorText( i18n( "%1 Content-Transfer-Encoding cannot correctly encode this message.", nameForEncoding( contentTransferEncoding->encoding() ) ) ); return false; } } else { // No specific CTE set. Choose the best one. Q_ASSERT( !allowed.isEmpty() ); contentTransferEncoding = new Headers::ContentTransferEncoding; contentTransferEncoding->setEncoding( allowed.first() ); } kDebug() << "Settled on encoding" << nameForEncoding( contentTransferEncoding->encoding() ); return true; } -ContentJob::ContentJob( QObject *parent ) - : Job( *new ContentJobPrivate( this ), parent ) +SinglepartJob::SinglepartJob( QObject *parent ) + : ContentJobBase( *new SinglepartJobPrivate( this ), parent ) { } -ContentJob::~ContentJob() +SinglepartJob::~SinglepartJob() { } -QByteArray ContentJob::data() const +QByteArray SinglepartJob::data() const { - Q_D( const ContentJob ); + Q_D( const SinglepartJob ); return d->data; } -void ContentJob::setData( const QByteArray &data ) +void SinglepartJob::setData( const QByteArray &data ) { - Q_D( ContentJob ); + Q_D( SinglepartJob ); d->data = data; } -Headers::ContentDisposition *ContentJob::contentDisposition() +Headers::ContentDisposition *SinglepartJob::contentDisposition() { - Q_D( ContentJob ); + Q_D( SinglepartJob ); if( !d->contentDisposition ) { d->contentDisposition = new Headers::ContentDisposition; } return d->contentDisposition; } -Headers::ContentTransferEncoding *ContentJob::contentTransferEncoding() +Headers::ContentID *SinglepartJob::contentID() { - Q_D( ContentJob ); + Q_D( SinglepartJob ); + if( !d->contentID ) { + d->contentID = new Headers::ContentID; + } + return d->contentID; +} + +Headers::ContentTransferEncoding *SinglepartJob::contentTransferEncoding() +{ + Q_D( SinglepartJob ); if( !d->contentTransferEncoding ) { d->contentTransferEncoding = new Headers::ContentTransferEncoding; } return d->contentTransferEncoding; } -Headers::ContentType *ContentJob::contentType() +Headers::ContentType *SinglepartJob::contentType() { - Q_D( ContentJob ); + Q_D( SinglepartJob ); if( !d->contentType ) { d->contentType = new Headers::ContentType; } return d->contentType; } -void ContentJob::process() +void SinglepartJob::process() { - Q_D( ContentJob ); + Q_D( SinglepartJob ); Q_ASSERT( d->resultContent == 0 ); // Not processed before. d->resultContent = new Content; if( !d->chooseCTE() ) { Q_ASSERT( error() ); emitResult(); return; } // Set headers. if( d->contentDisposition ) { d->resultContent->setHeader( d->contentDisposition ); d->contentDisposition->setParent( d->resultContent ); } + if( d->contentID ) { + d->resultContent->setHeader( d->contentID ); + d->contentID->setParent( d->resultContent ); + } Q_ASSERT( d->contentTransferEncoding ); // chooseCTE() created it if it didn't exist. { d->resultContent->setHeader( d->contentTransferEncoding ); d->contentTransferEncoding->setParent( d->resultContent ); kDebug() << "decoded" << d->contentTransferEncoding->decoded() << "needToEncode" << d->contentTransferEncoding->needToEncode(); } if( d->contentType ) { d->resultContent->setHeader( d->contentType ); d->contentType->setParent( d->resultContent ); } // Set data. d->resultContent->setBody( d->data ); kDebug() << "encoded content" << d->resultContent->encodedContent(); emitResult(); } -#include "contentjob.moc" +#include "singlepartjob.moc" diff --git a/messagecomposer/contentjob.h b/messagecomposer/singlepartjob.h similarity index 79% rename from messagecomposer/contentjob.h rename to messagecomposer/singlepartjob.h index 4fe4a4523..a9b2f5ad9 100644 --- a/messagecomposer/contentjob.h +++ b/messagecomposer/singlepartjob.h @@ -1,65 +1,67 @@ /* Copyright (c) 2009 Constantin Berzan 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. */ -#ifndef MESSAGECOMPOSER_CONTENTJOB_H -#define MESSAGECOMPOSER_CONTENTJOB_H +#ifndef MESSAGECOMPOSER_SINGLEPARTJOB_H +#define MESSAGECOMPOSER_SINGLEPARTJOB_H -#include "job.h" +#include "contentjobbase.h" #include "messagecomposer_export.h" namespace KMime { namespace Headers { class ContentDisposition; + class ContentID; class ContentTransferEncoding; class ContentType; } } namespace MessageComposer { -class ContentJobPrivate; +class SinglepartJobPrivate; /** */ -class MESSAGECOMPOSER_EXPORT ContentJob : public Job +class MESSAGECOMPOSER_EXPORT SinglepartJob : public ContentJobBase { Q_OBJECT public: - ContentJob( QObject *parent = 0 ); - virtual ~ContentJob(); + SinglepartJob( QObject *parent = 0 ); + virtual ~SinglepartJob(); QByteArray data() const; void setData( const QByteArray &data ); /// created on first call. delete them if you don't use the content KMime::Headers::ContentDisposition *contentDisposition(); + KMime::Headers::ContentID *contentID(); KMime::Headers::ContentTransferEncoding *contentTransferEncoding(); KMime::Headers::ContentType *contentType(); protected Q_SLOTS: virtual void process(); private: - Q_DECLARE_PRIVATE( ContentJob ) + Q_DECLARE_PRIVATE( SinglepartJob ) }; } #endif diff --git a/messagecomposer/skeletonmessagejob.cpp b/messagecomposer/skeletonmessagejob.cpp index 3e1f2bf74..7c6853bab 100644 --- a/messagecomposer/skeletonmessagejob.cpp +++ b/messagecomposer/skeletonmessagejob.cpp @@ -1,142 +1,151 @@ /* Copyright (c) 2009 Constantin Berzan 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. */ #include "skeletonmessagejob.h" #include "infopart.h" -#include "job_p.h" -#include "textpart.h" +#include "jobbase_p.h" #include +#include #include #include #include #include using namespace MessageComposer; using namespace KMime; -class MessageComposer::SkeletonMessageJobPrivate : public JobPrivate +class MessageComposer::SkeletonMessageJobPrivate : public JobBasePrivate { public: SkeletonMessageJobPrivate( SkeletonMessageJob *qq ) - : JobPrivate( qq ) + : JobBasePrivate( qq ) , infoPart( 0 ) + , message( 0 ) { } - InfoPart *infoPart; -}; - - - -SkeletonMessageJob::SkeletonMessageJob( InfoPart *infoPart, QObject *parent ) - : Job( *new SkeletonMessageJobPrivate( this ), parent ) -{ - Q_D( SkeletonMessageJob ); - d->infoPart = infoPart; -} - -SkeletonMessageJob::~SkeletonMessageJob() -{ -} + void doStart(); // slot -InfoPart *SkeletonMessageJob::infoPart() const -{ - Q_D( const SkeletonMessageJob ); - return d->infoPart; -} + InfoPart *infoPart; + Message *message; -void SkeletonMessageJob::setInfoPart( InfoPart *part ) -{ - Q_D( SkeletonMessageJob ); - d->infoPart = part; -} + Q_DECLARE_PUBLIC( SkeletonMessageJob ) +}; -Message *SkeletonMessageJob::message() const +void SkeletonMessageJobPrivate::doStart() { - Q_D( const SkeletonMessageJob ); - Q_ASSERT( d->resultContent ); - Q_ASSERT( dynamic_cast( d->resultContent ) ); - return static_cast( d->resultContent ); -} + Q_Q( SkeletonMessageJob ); -void SkeletonMessageJob::process() -{ - Q_D( SkeletonMessageJob ); - Q_ASSERT( d->infoPart ); - Q_ASSERT( d->subjobContents.isEmpty() ); // Cannot have subjobs. - Message *message = new Message; + Q_ASSERT( infoPart ); + Q_ASSERT( message == 0 ); + message = new Message; // From: { Headers::From *from = new Headers::From( message ); Types::Mailbox address; - address.fromUnicodeString( d->infoPart->from() ); + address.fromUnicodeString( infoPart->from() ); from->addAddress( address ); message->setHeader( from ); } // To: { Headers::To *to = new Headers::To( message ); - foreach( const QString &a, d->infoPart->to() ) { + foreach( const QString &a, infoPart->to() ) { Types::Mailbox address; address.fromUnicodeString( a ); to->addAddress( address ); } message->setHeader( to ); } // Cc: { Headers::Cc *cc = new Headers::Cc( message ); - foreach( const QString &a, d->infoPart->cc() ) { + foreach( const QString &a, infoPart->cc() ) { Types::Mailbox address; address.fromUnicodeString( a ); cc->addAddress( address ); } message->setHeader( cc ); } // Bcc: { Headers::Bcc *bcc = new Headers::Bcc( message ); - foreach( const QString &a, d->infoPart->bcc() ) { + foreach( const QString &a, infoPart->bcc() ) { Types::Mailbox address; address.fromUnicodeString( a ); bcc->addAddress( address ); } message->setHeader( bcc ); } // Subject: { Headers::Subject *subject = new Headers::Subject( message ); - subject->fromUnicodeString( d->infoPart->subject(), QByteArray() ); // TODO charset?? + subject->fromUnicodeString( infoPart->subject(), "utf-8" ); + // TODO should we be more specific about the charset? message->setHeader( subject ); } - d->resultContent = message; - emitResult(); + q->emitResult(); // Success. +} + + +SkeletonMessageJob::SkeletonMessageJob( InfoPart *infoPart, QObject *parent ) + : JobBase( *new SkeletonMessageJobPrivate( this ), parent ) +{ + Q_D( SkeletonMessageJob ); + d->infoPart = infoPart; +} + +SkeletonMessageJob::~SkeletonMessageJob() +{ +} + +InfoPart *SkeletonMessageJob::infoPart() const +{ + Q_D( const SkeletonMessageJob ); + return d->infoPart; +} + +void SkeletonMessageJob::setInfoPart( InfoPart *part ) +{ + Q_D( SkeletonMessageJob ); + d->infoPart = part; +} + +Message *SkeletonMessageJob::message() const +{ + Q_D( const SkeletonMessageJob ); + return d->message; +} + +void SkeletonMessageJob::start() +{ + QTimer::singleShot( 0, this, SLOT(doStart()) ); } #include "skeletonmessagejob.moc" diff --git a/messagecomposer/skeletonmessagejob.h b/messagecomposer/skeletonmessagejob.h index b1b8eddd6..1fff4cadb 100644 --- a/messagecomposer/skeletonmessagejob.h +++ b/messagecomposer/skeletonmessagejob.h @@ -1,63 +1,61 @@ /* Copyright (c) 2009 Constantin Berzan - Based on ideas by Stephen Kelly. 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. */ #ifndef MESSAGECOMPOSER_SKELETONMESSAGEJOB_H #define MESSAGECOMPOSER_SKELETONMESSAGEJOB_H -#include "job.h" +#include "jobbase.h" #include "messagecomposer_export.h" namespace KMime { class Message; } namespace MessageComposer { class SkeletonMessageJobPrivate; class InfoPart; /** A message containing only the headers... */ -class MESSAGECOMPOSER_EXPORT SkeletonMessageJob : public Job +class MESSAGECOMPOSER_EXPORT SkeletonMessageJob : public JobBase { Q_OBJECT public: explicit SkeletonMessageJob( InfoPart *infoPart = 0, QObject *parent = 0 ); virtual ~SkeletonMessageJob(); InfoPart *infoPart() const; void setInfoPart( InfoPart *part ); KMime::Message *message() const; - // TODO I think there is a way in C++ to make content() private, even if it's public - // in the base class. - protected Q_SLOTS: - virtual void process(); + virtual void start(); private: Q_DECLARE_PRIVATE( SkeletonMessageJob ) + + Q_PRIVATE_SLOT( d_func(), void doStart() ) }; } // namespace MessageComposer #endif diff --git a/messagecomposer/tests/CMakeLists.txt b/messagecomposer/tests/CMakeLists.txt index a21b1cdd7..2b23c1c38 100644 --- a/messagecomposer/tests/CMakeLists.txt +++ b/messagecomposer/tests/CMakeLists.txt @@ -1,28 +1,39 @@ set( EXECUTABLE_OUTPUT_PATH ${CMAKE_CURRENT_BINARY_DIR} ) include_directories ( ${Boost_INCLUDE_DIR} ) -# convenience macro to add messagecomposer unit tests +# Location of the attachments to test. +set( attachments_root "QLatin1String( \"${CMAKE_CURRENT_SOURCE_DIR}/attachments/\" )" ) +add_definitions( -DPATH_ATTACHMENTS='${attachments_root}' ) + +# Convenience macro to add messagecomposer unit tests. macro( add_messagecomposer_test _source ) set( _test ${_source} ) get_filename_component( _name ${_source} NAME_WE ) kde4_add_unit_test( ${_name} TESTNAME messagecomposer-${_name} ${_test} ) target_link_libraries( ${_name} kmime messagecomposer ${QT_QTTEST_LIBRARY} ${QT_QTGUI_LIBRARY} ${QT_QTCORE_LIBRARY} ${KDE4_KDEUI_LIBS} ) endmacro( add_messagecomposer_test ) + + # Utility stuff. -add_messagecomposer_test( behaviourtest.cpp ) +add_messagecomposer_test( utiltest.cpp ) -# Basic jobs. -add_messagecomposer_test( contentjobtest.cpp ) +# Non-content jobs. +add_messagecomposer_test( skeletonmessagejobtest.cpp ) +add_messagecomposer_test( attachmentfrommimecontentjobtest.cpp ) +add_messagecomposer_test( attachmentfromurljobtest.cpp ) +add_messagecomposer_test( attachmentcompressjobtest.cpp ) + +# Basic content jobs. +add_messagecomposer_test( singlepartjobtest.cpp ) add_messagecomposer_test( multipartjobtest.cpp ) -# More complex jobs. -add_messagecomposer_test( skeletonmessagejobtest.cpp ) +# More complex content jobs. add_messagecomposer_test( maintextjobtest.cpp ) # Composer. add_messagecomposer_test( composertest.cpp ) diff --git a/messagecomposer/tests/attachmentcompressjobtest.cpp b/messagecomposer/tests/attachmentcompressjobtest.cpp new file mode 100644 index 000000000..148e1bbdc --- /dev/null +++ b/messagecomposer/tests/attachmentcompressjobtest.cpp @@ -0,0 +1,108 @@ +/* + Copyright (c) 2009 Constantin Berzan + + 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. +*/ + +#include "attachmentcompressjobtest.h" +#include "qtest_messagecomposer.h" + +#include +#include +#include + +#include +#include +#include +using namespace MessageComposer; + +QTEST_KDEMAIN( AttachmentCompressJobTest, NoGUI ) + +void AttachmentCompressJobTest::testCompress() +{ + // Some data. + QByteArray data; + for( int i = 0; i < 100; i++ ) { + data += "This is some highly compressible text...\n"; + } + const QString name = QString::fromLatin1( "name.txt" ); + const QString description = QString::fromLatin1( "description" ); + + // Create the original part. + Composer *composer = new Composer; + AttachmentPart *origPart = new AttachmentPart( composer ); + origPart->setName( name ); + origPart->setDescription( description ); + origPart->setMimeType( "text/plain" ); + origPart->setEncoding( KMime::Headers::CE7Bit ); + QVERIFY( !origPart->isAutoEncoding() ); + origPart->setData( data ); + QVERIFY( !origPart->isCompressed() ); + + // Compress the part and verify it. + AttachmentCompressJob *cjob = new AttachmentCompressJob( origPart, composer ); + VERIFYEXEC( cjob ); + QCOMPARE( cjob->originalPart(), origPart ); + AttachmentPart *zipPart = cjob->compressedPart(); + //kDebug() << data; + //kDebug() << zipPart->data(); + QVERIFY( zipPart->isAutoEncoding() ); + QVERIFY( zipPart->isCompressed() ); + QCOMPARE( zipPart->name(), name + QString::fromLatin1( ".zip" ) ); + QCOMPARE( zipPart->description(), description ); + QCOMPARE( zipPart->mimeType(), QByteArray( "application/zip" ) ); + + // Uncompress the data and verify it. + // (Stuff below is stolen from KMail code.) + QByteArray zipData = zipPart->data(); + QBuffer buffer( &zipData ); + KZip zip( &buffer ); + QVERIFY( zip.open( QIODevice::ReadOnly ) ); + const KArchiveDirectory *dir = zip.directory(); + QCOMPARE( dir->entries().count(), 1 ); + const KZipFileEntry *entry = (KZipFileEntry*)dir->entry( dir->entries()[0] ); + QCOMPARE( entry->data(), data ); + QCOMPARE( entry->name(), name ); + zip.close(); +} + +void AttachmentCompressJobTest::testCompressedSizeLarger() +{ + // Some data. + QByteArray data( "This is short enough that compressing it is not efficient." ); + const QString name = QString::fromLatin1( "name.txt" ); + const QString description = QString::fromLatin1( "description" ); + + // Create the original part. + Composer *composer = new Composer; + composer->globalPart()->setGuiEnabled( false ); + AttachmentPart *origPart = new AttachmentPart( composer ); + origPart->setName( name ); + origPart->setDescription( description ); + origPart->setMimeType( "text/plain" ); + origPart->setEncoding( KMime::Headers::CE7Bit ); + QVERIFY( !origPart->isAutoEncoding() ); + origPart->setData( data ); + QVERIFY( !origPart->isCompressed() ); + + // Try to compress the part (the job should fail). + AttachmentCompressJob *cjob = new AttachmentCompressJob( origPart, composer ); + QVERIFY( cjob->warnCompressedSizeLarger() ); + QVERIFY( !cjob->exec() ); + QCOMPARE( cjob->error(), int( JobBase::UserError ) ); +} + +#include "attachmentcompressjobtest.moc" diff --git a/messagecomposer/behaviour_p.h b/messagecomposer/tests/attachmentcompressjobtest.h similarity index 77% rename from messagecomposer/behaviour_p.h rename to messagecomposer/tests/attachmentcompressjobtest.h index 34dcf87af..ef3a2790a 100644 --- a/messagecomposer/behaviour_p.h +++ b/messagecomposer/tests/attachmentcompressjobtest.h @@ -1,33 +1,33 @@ /* Copyright (c) 2009 Constantin Berzan 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. */ -#include - -#ifndef MESSAGECOMPOSER_BEHAVIOUR_P_H -#define MESSAGECOMPOSER_BEHAVIOUR_P_H - -namespace MessageComposer { - -/** - @internal -*/ - -} +#ifndef ATTACHMENTCOMPRESSJOBTEST_H +#define ATTACHMENTCOMPRESSJOBTEST_H + +#include + +class AttachmentCompressJobTest : public QObject +{ + Q_OBJECT + private Q_SLOTS: + void testCompress(); + void testCompressedSizeLarger(); +}; #endif diff --git a/messagecomposer/tests/attachmentfrommimecontentjobtest.cpp b/messagecomposer/tests/attachmentfrommimecontentjobtest.cpp new file mode 100644 index 000000000..d65973af1 --- /dev/null +++ b/messagecomposer/tests/attachmentfrommimecontentjobtest.cpp @@ -0,0 +1,73 @@ +/* + Copyright (c) 2009 Constantin Berzan + + 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. +*/ + +#include "attachmentfrommimecontentjobtest.h" +#include "qtest_messagecomposer.h" + +#include + +#include +#include +#include +using namespace MessageComposer; + +QTEST_KDEMAIN( AttachmentFromMimeContentJobTest, NoGUI ) + +void AttachmentFromMimeContentJobTest::testAttachment() +{ + const QByteArray mimeType( "x-some/x-type" ); + const QString name( "name abcd" ); + const QString description( "description" ); + const QString charset( "utf-8" ); + const QString fileName( "filename abcd" ); + const Headers::contentEncoding encoding = Headers::CEquPr; + const Headers::contentDisposition disposition = Headers::CDinline; + const QByteArray data( "ocean soul" ); + + KMime::Content *content = new KMime::Content; + content->contentType()->setMimeType( mimeType ); + content->contentType()->setName( name ); + content->contentType()->setCharset( charset ); + content->contentTransferEncoding()->setEncoding( encoding ); + content->contentDisposition()->setDisposition( disposition ); + content->contentDisposition()->setFileName( fileName ); + content->contentDescription()->setDescription( description, charset ); + content->assemble(); + + Composer *composer = new Composer; + composer->globalPart()->setGuiEnabled( false ); + AttachmentFromMimeContentJob *job = new AttachmentFromMimeContentJob( content, composer ); + VERIFYEXEC( job ); + delete content; + content = 0; + AttachmentPart *part = job->attachmentPart(); + delete job; + job = 0; + + QCOMPARE( part->mimeType(), mimeType ); + QCOMPARE( part->name(), name ); + QCOMPARE( part->description(), description ); + //QCOMPARE( part->charset(), charset ); // TODO will probably need charsets in AttachmentPart :( + QCOMPARE( part->fileName(), fileName ); + QVERIFY( part->encoding() == encoding ); + QVERIFY( part->isInline() ); + QCOMPARE( part->data(), data ); +} + +#include "attachmentfrommimecontentjobtest.moc" diff --git a/messagecomposer/tests/behaviourtest.h b/messagecomposer/tests/attachmentfrommimecontentjobtest.h similarity index 81% copy from messagecomposer/tests/behaviourtest.h copy to messagecomposer/tests/attachmentfrommimecontentjobtest.h index 2317b3f51..167d350d3 100644 --- a/messagecomposer/tests/behaviourtest.h +++ b/messagecomposer/tests/attachmentfrommimecontentjobtest.h @@ -1,32 +1,33 @@ /* Copyright (c) 2009 Constantin Berzan 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. */ -#ifndef BEHAVIOURTEST_H -#define BEHAVIOURTEST_H +#ifndef ATTACHMENTFROMMIMECONTENTJOBTEST_H +#define ATTACHMENTFROMMIMECONTENTJOBTEST_H #include -class BehaviourTest : public QObject +// 33-byte class names say I suck? +class AttachmentFromMimeContentJobTest : public QObject { Q_OBJECT private Q_SLOTS: - void testApi(); + void testAttachment(); }; #endif diff --git a/messagecomposer/tests/attachmentfromurljobtest.cpp b/messagecomposer/tests/attachmentfromurljobtest.cpp new file mode 100644 index 000000000..20e4710c5 --- /dev/null +++ b/messagecomposer/tests/attachmentfromurljobtest.cpp @@ -0,0 +1,90 @@ +/* + Copyright (c) 2009 Constantin Berzan + + 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. +*/ + +#include "attachmentfromurljobtest.h" +#include "qtest_messagecomposer.h" + +#include + +#include +#include +#include +using namespace MessageComposer; + +QTEST_KDEMAIN( AttachmentFromUrlJobTest, NoGUI ) + +void AttachmentFromUrlJobTest::testAttachments_data() +{ + QTest::addColumn( "url" ); + QTest::addColumn( "filename" ); + QTest::addColumn( "mimetype" ); + + // PATH_ATTACHMENTS is defined by CMake. + QTest::newRow( "png image" ) << KUrl::fromPath( PATH_ATTACHMENTS + QString::fromLatin1( "image.png" ) ) + << QString::fromLatin1( "image.png" ) + << QByteArray( "image/png" ); + QTest::newRow( "pdf doc" ) << KUrl::fromPath( PATH_ATTACHMENTS + QString::fromLatin1( "doc.pdf" ) ) + << QString::fromLatin1( "doc.pdf" ) + << QByteArray( "application/pdf" ); + QTest::newRow( "text file" ) << KUrl::fromPath( PATH_ATTACHMENTS + QString::fromLatin1( "file.txt" ) ) + << QString::fromLatin1( "file.txt" ) + << QByteArray( "text/plain" ); +} + +void AttachmentFromUrlJobTest::testAttachments() +{ + QFETCH( KUrl, url ); + QFETCH( QString, filename ); + QFETCH( QByteArray, mimetype ); + + QFile file( url.path() ); + QVERIFY( file.open(QIODevice::ReadOnly) ); + QByteArray data = file.readAll(); + file.close(); + + Composer *composer = new Composer; + composer->globalPart()->setGuiEnabled( false ); + AttachmentFromUrlJob *ljob = new AttachmentFromUrlJob( url, composer ); + VERIFYEXEC( ljob ); + AttachmentPart *part = ljob->attachmentPart(); + delete ljob; + ljob = 0; + + QCOMPARE( part->name(), filename ); + QCOMPARE( part->filename(), filename ); + QVERIFY( !part->isInline() ); + QCOMPARE( part->mimeType(), mimetype ); + QCOMPARE( part->data(), data ); +} + +void AttachmentFromUrlJobTest::testAttachmentTooBig() +{ + const KUrl url = KUrl::fromPath( PATH_ATTACHMENTS + QString::fromLatin1( "doc.pdf" ) ); + const QString name = QString::fromLatin1( "doc.pdf" ); + const QByteArray mimetype( "application/pdf" ); + + Composer *composer = new Composer; + composer->globalPart()->setGuiEnabled( false ); + AttachmentFromUrlJob *ljob = new AttachmentFromUrlJob( url, composer ); + ljob->setMaximumAllowedSize( 1024 ); // 1KiB, whereas the file is >9KiB. + QVERIFY( !ljob->exec() ); + QCOMPARE( ljob->error(), int( JobBase::UserError ) ); +} + +#include "attachmentfromurljobtest.moc" diff --git a/messagecomposer/tests/behaviourtest.h b/messagecomposer/tests/attachmentfromurljobtest.h similarity index 80% copy from messagecomposer/tests/behaviourtest.h copy to messagecomposer/tests/attachmentfromurljobtest.h index 2317b3f51..d4b837d4f 100644 --- a/messagecomposer/tests/behaviourtest.h +++ b/messagecomposer/tests/attachmentfromurljobtest.h @@ -1,32 +1,34 @@ /* Copyright (c) 2009 Constantin Berzan 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. */ -#ifndef BEHAVIOURTEST_H -#define BEHAVIOURTEST_H +#ifndef ATTACHMENTFROMURLJOBTEST_H +#define ATTACHMENTFROMURLJOBTEST_H #include -class BehaviourTest : public QObject +class AttachmentFromUrlJobTest : public QObject { Q_OBJECT private Q_SLOTS: - void testApi(); + void testAttachments_data(); + void testAttachments(); + void testAttachmentTooBig(); }; #endif diff --git a/messagecomposer/tests/attachments/doc.pdf b/messagecomposer/tests/attachments/doc.pdf new file mode 100644 index 000000000..044b320a3 Binary files /dev/null and b/messagecomposer/tests/attachments/doc.pdf differ diff --git a/messagecomposer/tests/attachments/file.txt b/messagecomposer/tests/attachments/file.txt new file mode 100644 index 000000000..ae572727c --- /dev/null +++ b/messagecomposer/tests/attachments/file.txt @@ -0,0 +1,2 @@ +some plain ascii text... + diff --git a/messagecomposer/tests/attachments/image.png b/messagecomposer/tests/attachments/image.png new file mode 100644 index 000000000..37fd27a33 Binary files /dev/null and b/messagecomposer/tests/attachments/image.png differ diff --git a/messagecomposer/tests/behaviourtest.cpp b/messagecomposer/tests/behaviourtest.cpp deleted file mode 100644 index 99e7d6843..000000000 --- a/messagecomposer/tests/behaviourtest.cpp +++ /dev/null @@ -1,47 +0,0 @@ -/* - Copyright (c) 2009 Constantin Berzan - - 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. -*/ - -#include "behaviourtest.h" - -#include - -#include -using namespace MessageComposer; - -QTEST_KDEMAIN( BehaviourTest, NoGUI ) - -void BehaviourTest::testApi() -{ - Behaviour beh; // Has sending behaviour by default. - QVERIFY( !beh.isActionEnabled( Behaviour::CustomHeaders ) ); - beh.enableAction( Behaviour::CustomHeaders ); - QVERIFY( beh.isActionEnabled( Behaviour::CustomHeaders ) ); - beh.enableAction( Behaviour::CustomHeaders, false ); - QVERIFY( !beh.isActionEnabled( Behaviour::CustomHeaders ) ); - beh.enableAction( Behaviour::CustomHeaders ); - QVERIFY( beh.isActionEnabled( Behaviour::CustomHeaders ) ); - beh.disableAction( Behaviour::CustomHeaders ); - QVERIFY( !beh.isActionEnabled( Behaviour::CustomHeaders ) ); - - Behaviour send = Behaviour::behaviourForSending(); - QCOMPARE( beh.isActionEnabled( Behaviour::CustomHeaders ), - send.isActionEnabled( Behaviour::CustomHeaders ) ); -} - -#include "behaviourtest.moc" diff --git a/messagecomposer/tests/composertest.cpp b/messagecomposer/tests/composertest.cpp index c41e0df83..b090d6bf8 100644 --- a/messagecomposer/tests/composertest.cpp +++ b/messagecomposer/tests/composertest.cpp @@ -1,76 +1,79 @@ /* Copyright (c) 2009 Constantin Berzan 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. */ #include "composertest.h" #include #include #include using namespace KMime; #include +#include #include #include using namespace MessageComposer; QTEST_KDEMAIN( ComposerTest, NoGUI ) void ComposerTest::testCTEErrors() { // First test that the composer succeeds at all. { Composer *composer = new Composer; - composer->behaviour().enableAction( Behaviour::UseFallbackCharset ); + composer->globalPart()->setFallbackCharsetEnabled( true ); composer->infoPart()->setFrom( QString::fromLatin1( "me@me.me" ) ); composer->infoPart()->setTo( QStringList( QString::fromLatin1( "you@you.you" ) ) ); composer->textPart()->setWrappedPlainText( QString::fromLatin1( "sample content" ) ); QVERIFY( composer->exec() ); QCOMPARE( composer->messages().count(), 1 ); kDebug() << composer->messages().first()->message()->encodedContent(); } +#if 0 // test with attachments // unsupported CTE -> error. { Composer *composer = new Composer; - composer->behaviour().enableAction( Behaviour::UseFallbackCharset ); + composer->globalPart()->setFallbackCharsetEnabled( true ); composer->infoPart()->setFrom( QString::fromLatin1( "me@me.me" ) ); composer->infoPart()->setTo( QStringList( QString::fromLatin1( "you@you.you" ) ) ); composer->textPart()->setWrappedPlainText( QString::fromLatin1( "sample content" ) ); - composer->textPart()->setOverrideTransferEncoding( Headers::CEbinary ); + composer->textPart()->setOverrideTransferEncoding( Headers::CEbinary ); // DEAD DEAD DEAD QVERIFY( !composer->exec() ); QCOMPARE( composer->error(), int( Job::BugError ) ); kDebug() << composer->errorString(); } - // 8bit part when not EightBitTransport -> error. + // 8bit part when is8BitAllowed false -> error. { Composer *composer = new Composer; composer->behaviour().enableAction( Behaviour::UseFallbackCharset ); composer->infoPart()->setFrom( QString::fromLatin1( "me@me.me" ) ); composer->infoPart()->setTo( QStringList( QString::fromLatin1( "you@you.you" ) ) ); composer->textPart()->setWrappedPlainText( QString::fromLatin1( "sample content" ) ); - composer->textPart()->setOverrideTransferEncoding( Headers::CE8Bit ); + composer->textPart()->setOverrideTransferEncoding( Headers::CE8Bit ); // DEAD DEAD DEAD QVERIFY( !composer->exec() ); QCOMPARE( composer->error(), int( Job::BugError ) ); kDebug() << composer->errorString(); } +#endif } #include "composertest.moc" diff --git a/messagecomposer/tests/maintextjobtest.cpp b/messagecomposer/tests/maintextjobtest.cpp index e6c30cd3e..273d35f50 100644 --- a/messagecomposer/tests/maintextjobtest.cpp +++ b/messagecomposer/tests/maintextjobtest.cpp @@ -1,184 +1,286 @@ /* Copyright (c) 2009 Constantin Berzan 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. */ #include "maintextjobtest.h" #include #include +#include #include #include using namespace KMime; #include +#include #include #include using namespace MessageComposer; -QTEST_KDEMAIN( MainTextJobTest, NoGUI ) +#include + +QTEST_KDEMAIN( MainTextJobTest, GUI ) void MainTextJobTest::testPlainText() { Composer *composer = new Composer; - composer->behaviour().disableAction( Behaviour::UseGui ); - TextPart *textPart = new TextPart; - QString data = QString::fromLatin1( "they said their nevers they slept their dream" ); + composer->globalPart()->setGuiEnabled( false ); QList charsets; charsets << "us-ascii" << "utf-8"; + composer->globalPart()->setCharsets( charsets ); + TextPart *textPart = new TextPart; + QString data = QString::fromLatin1( "they said their nevers they slept their dream" ); textPart->setWrappedPlainText( data ); - textPart->setCharsets( charsets ); MainTextJob *mjob = new MainTextJob( textPart, composer ); QVERIFY( mjob->exec() ); Content *result = mjob->content(); result->assemble(); kDebug() << result->encodedContent(); QVERIFY( result->contentType( false ) ); QCOMPARE( result->contentType()->mimeType(), QByteArray( "text/plain" ) ); QCOMPARE( result->contentType()->charset(), QByteArray( "us-ascii" ) ); QCOMPARE( QString::fromLatin1( result->body() ), data ); } void MainTextJobTest::testWrappingErrors() { { Composer *composer = new Composer; - composer->behaviour().disableAction( Behaviour::UseGui ); - composer->behaviour().disableAction( Behaviour::UseWrapping ); - composer->behaviour().enableAction( Behaviour::UseFallbackCharset ); + composer->globalPart()->setGuiEnabled( false ); + composer->globalPart()->setFallbackCharsetEnabled( true ); TextPart *textPart = new TextPart; QString data = QString::fromLatin1( "they said their nevers they slept their dream" ); + textPart->setWordWrappingEnabled( false ); textPart->setWrappedPlainText( data ); MainTextJob *mjob = new MainTextJob( textPart, composer ); QVERIFY( !mjob->exec() ); // error: not UseWrapping but given only wrapped text - QCOMPARE( mjob->error(), int( Job::BugError ) ); + QCOMPARE( mjob->error(), int( JobBase::BugError ) ); } { Composer *composer = new Composer; - composer->behaviour().disableAction( Behaviour::UseGui ); - composer->behaviour().enableAction( Behaviour::UseWrapping ); - composer->behaviour().enableAction( Behaviour::UseFallbackCharset ); + composer->globalPart()->setGuiEnabled( false ); + composer->globalPart()->setFallbackCharsetEnabled( true ); TextPart *textPart = new TextPart; + textPart->setWordWrappingEnabled( true ); QString data = QString::fromLatin1( "they said their nevers they slept their dream" ); textPart->setCleanPlainText( data ); MainTextJob *mjob = new MainTextJob( textPart, composer ); QVERIFY( !mjob->exec() ); // error: UseWrapping but given only clean text - QCOMPARE( mjob->error(), int( Job::BugError ) ); + QCOMPARE( mjob->error(), int( JobBase::BugError ) ); } } void MainTextJobTest::testCustomCharset() { Composer *composer = new Composer; - composer->behaviour().disableAction( Behaviour::UseGui ); + composer->globalPart()->setGuiEnabled( false ); + QByteArray charset( "iso-8859-2" ); + composer->globalPart()->setCharsets( QList() << charset ); TextPart *textPart = new TextPart; QString data = QString::fromUtf8( "şi el o să se-nchidă cu o frunză de pelin" ); - QByteArray charset( "iso-8859-2" ); textPart->setWrappedPlainText( data ); - textPart->setCharsets( QList() << charset ); MainTextJob *mjob = new MainTextJob( textPart, composer ); QVERIFY( mjob->exec() ); Content *result = mjob->content(); result->assemble(); kDebug() << result->encodedContent(); QVERIFY( result->contentType( false ) ); QCOMPARE( result->contentType()->mimeType(), QByteArray( "text/plain" ) ); QCOMPARE( result->contentType()->charset(), charset ); QByteArray outData = result->body(); QTextCodec *codec = QTextCodec::codecForName( charset ); QVERIFY( codec ); QCOMPARE( codec->toUnicode( outData ), data ); } void MainTextJobTest::testNoCharset() { Composer *composer = new Composer; - composer->behaviour().disableAction( Behaviour::UseGui ); + QVERIFY( !composer->globalPart()->isFallbackCharsetEnabled() ); + composer->globalPart()->setGuiEnabled( false ); TextPart *textPart = new TextPart; QString data = QString::fromLatin1( "do you still play the accordion?" ); textPart->setWrappedPlainText( data ); MainTextJob *mjob = new MainTextJob( textPart, composer ); QVERIFY( !mjob->exec() ); // Error. - QCOMPARE( mjob->error(), int( Job::BugError ) ); + QCOMPARE( mjob->error(), int( JobBase::BugError ) ); kDebug() << mjob->errorString(); } void MainTextJobTest::testBadCharset() { Composer *composer = new Composer; - composer->behaviour().disableAction( Behaviour::UseGui ); + composer->globalPart()->setGuiEnabled( false ); + QByteArray charset( "us-ascii" ); // Cannot handle Romanian chars. + composer->globalPart()->setCharsets( QList() << charset ); TextPart *textPart = new TextPart; QString data = QString::fromUtf8( "el a plâns peste ţară cu lacrima limbii noastre" ); - QByteArray charset( "us-ascii" ); // Cannot handle Romanian chars. textPart->setWrappedPlainText( data ); - textPart->setCharsets( QList() << charset ); MainTextJob *mjob = new MainTextJob( textPart, composer ); QVERIFY( !mjob->exec() ); // Error. - QCOMPARE( mjob->error(), int( Job::UserError ) ); + QCOMPARE( mjob->error(), int( JobBase::UserError ) ); kDebug() << mjob->errorString(); } void MainTextJobTest::testFallbackCharset() { Composer *composer = new Composer; - composer->behaviour().disableAction( Behaviour::UseGui ); - composer->behaviour().enableAction( Behaviour::UseFallbackCharset ); + composer->globalPart()->setGuiEnabled( false ); + composer->globalPart()->setFallbackCharsetEnabled( true ); TextPart *textPart = new TextPart; QString data = QString::fromLatin1( "and when he falleth..." ); textPart->setWrappedPlainText( data ); MainTextJob *mjob = new MainTextJob( textPart, composer ); QVERIFY( mjob->exec() ); Content *result = mjob->content(); result->assemble(); kDebug() << result->encodedContent(); QVERIFY( result->contentType( false ) ); QCOMPARE( result->contentType()->mimeType(), QByteArray( "text/plain" ) ); - QCOMPARE( result->contentType()->charset(), QByteArray( "utf-8" ) ); // Fallback is UTF-8. + QCOMPARE( result->contentType()->charset(), QByteArray( "us-ascii" ) ); // Fallback is us-ascii or utf8. QCOMPARE( QString::fromLatin1( result->body() ), data ); } -void MainTextJobTest::testOverrideCTE() +void MainTextJobTest::testHtml() { + QLatin1String originalHtml( "Test with formatting...
The end." ); + KPIMTextEdit::TextEdit editor; + editor.setTextOrHtml( originalHtml ); + QVERIFY( editor.isFormattingUsed() ); + Composer *composer = new Composer; - QVERIFY( !composer->behaviour().isActionEnabled( Behaviour::EightBitTransport ) ); - composer->behaviour().enableAction( Behaviour::UseFallbackCharset ); + composer->globalPart()->setGuiEnabled( false ); + composer->globalPart()->setFallbackCharsetEnabled( true ); TextPart *textPart = new TextPart; + textPart->setWordWrappingEnabled( false ); + textPart->setCleanPlainText( editor.toCleanPlainText() ); + textPart->setCleanHtml( editor.toCleanHtml() ); + MainTextJob *mjob = new MainTextJob( textPart, composer ); + QVERIFY( mjob->exec() ); + Content *result = mjob->content(); + result->assemble(); + kDebug() << result->encodedContent(); - // 8bit if asked for and allowed. + // multipart/alternative { - composer->behaviour().enableAction( Behaviour::EightBitTransport ); - QString data = QString::fromUtf8( "[ăîşţâ]" ); - textPart->setWrappedPlainText( data ); - // Force it to use an 8bit encoding: - QByteArray charset( "iso-8859-2" ); - textPart->setCharsets( QList() << charset ); - MainTextJob *mjob = new MainTextJob( textPart, composer ); - QVERIFY( mjob->exec() ); - Content *result = mjob->content(); - result->assemble(); - kDebug() << result->encodedContent(); - QVERIFY( result->contentTransferEncoding( false ) ); - QCOMPARE( result->contentTransferEncoding()->encoding(), Headers::CE8Bit ); - QTextCodec *codec = QTextCodec::codecForName( charset ); - QVERIFY( codec ); - QCOMPARE( codec->toUnicode( result->body() ), data ); + QVERIFY( result->contentType( false ) ); + QCOMPARE( result->contentType()->mimeType(), QByteArray( "multipart/alternative" ) ); + QCOMPARE( result->contents().count(), 2 ); + // text/plain + { + Content *plain = result->contents().at( 0 ); + QVERIFY( plain->contentType( false ) ); + QCOMPARE( plain->contentType()->mimeType(), QByteArray( "text/plain" ) ); + QCOMPARE( QString::fromLatin1( plain->body() ), editor.toCleanPlainText() ); + } + // text/html + { + Content *html = result->contents().at( 1 ); + QVERIFY( html->contentType( false ) ); + QCOMPARE( html->contentType()->mimeType(), QByteArray( "text/html" ) ); + // The editor adds extra Html stuff, so we can't compare to originalHtml. + QCOMPARE( QLatin1String( html->body() ), editor.toCleanHtml() ); + } + } +} + +void MainTextJobTest::testHtmlWithImages() +{ + KPIMTextEdit::TextEdit editor; + QString image1 = KIconLoader::global()->iconPath( QLatin1String( "folder-new" ), KIconLoader::Small, false ); + QString image2 = KIconLoader::global()->iconPath( QLatin1String( "message" ), KIconLoader::Small, false ); + QString data = QString::fromLatin1( "dust in the wind" ); + editor.setTextOrHtml( data ); + editor.addImage( image1 ); + editor.addImage( image2 ); + KPIMTextEdit::ImageList images = editor.embeddedImages(); + QCOMPARE( images.count(), 2 ); + QString cid1 = images[0]->contentID; + QString cid2 = images[1]->contentID; + QString name1 = images[0]->imageName; + QString name2 = images[1]->imageName; + + Composer *composer = new Composer; + composer->globalPart()->setGuiEnabled( false ); + composer->globalPart()->setFallbackCharsetEnabled( true ); + TextPart *textPart = new TextPart; + textPart->setWordWrappingEnabled( false ); + textPart->setCleanPlainText( editor.toCleanPlainText() ); + textPart->setCleanHtml( editor.toCleanHtml() ); + textPart->setEmbeddedImages( editor.embeddedImages() ); + MainTextJob *mjob = new MainTextJob( textPart, composer ); + QVERIFY( mjob->exec() ); + Content *result = mjob->content(); + result->assemble(); + kDebug() << result->encodedContent(); + + // multipart/related + { + QVERIFY( result->contentType( false ) ); + QCOMPARE( result->contentType()->mimeType(), QByteArray( "multipart/related" ) ); + QCOMPARE( result->contents().count(), 3 ); + // multipart/alternative + { + Content *alternative = result->contents().at( 0 ); + QVERIFY( alternative->contentType( false ) ); + QCOMPARE( alternative->contentType()->mimeType(), QByteArray( "multipart/alternative" ) ); + QCOMPARE( alternative->contents().count(), 2 ); + // text/plain + { + Content *plain = alternative->contents().at( 0 ); + QCOMPARE( plain->contentType()->mimeType(), QByteArray( "text/plain" ) ); + QCOMPARE( QString::fromLatin1( plain->body() ), data ); + } + // text/html + { + Content *html = alternative->contents().at( 1 ); + QCOMPARE( html->contentType()->mimeType(), QByteArray( "text/html" ) ); + QString data = QString::fromLatin1( html->body() ); + int idx1 = data.indexOf( QString::fromLatin1( "cid:%1" ).arg( cid1 ) ); + int idx2 = data.indexOf( QString::fromLatin1( "cid:%1" ).arg( cid2 ) ); + QVERIFY( idx1 > 0 ); + QVERIFY( idx2 > 0 ); + QVERIFY( idx1 < idx2 ); + } + } + // First image/png + { + Content *image = result->contents().at( 1 ); + QVERIFY( image->contentType( false ) ); + QCOMPARE( image->contentType()->mimeType(), QByteArray( "image/png" ) ); + QCOMPARE( image->contentType()->name(), name1 ); + const Headers::ContentID *cid = image->header(); + QVERIFY( cid ); + QCOMPARE( cid->identifier(), cid1.toLatin1() ); + } + // Second image/png + { + Content *image = result->contents().at( 2 ); + QVERIFY( image->contentType( false ) ); + QCOMPARE( image->contentType()->mimeType(), QByteArray( "image/png" ) ); + QCOMPARE( image->contentType()->name(), name2 ); + const Headers::ContentID *cid = image->header(); + QVERIFY( cid ); + QCOMPARE( cid->identifier(), cid2.toLatin1() ); + } } } #include "maintextjobtest.moc" diff --git a/messagecomposer/tests/maintextjobtest.h b/messagecomposer/tests/maintextjobtest.h index ddcab2364..9c5b4fa3d 100644 --- a/messagecomposer/tests/maintextjobtest.h +++ b/messagecomposer/tests/maintextjobtest.h @@ -1,43 +1,44 @@ /* Copyright (c) 2009 Constantin Berzan 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. */ #ifndef MAINTEXTJOBTEST_H #define MAINTEXTJOBTEST_H #include class MainTextJobTest : public QObject { Q_OBJECT private Q_SLOTS: // "text/plain" tests: void testPlainText(); void testWrappingErrors(); // charset tests: void testCustomCharset(); void testNoCharset(); void testBadCharset(); void testFallbackCharset(); - // Content-Transfer-Encoding tests: - void testOverrideCTE(); + // html tests: + void testHtml(); + void testHtmlWithImages(); }; #endif diff --git a/messagecomposer/tests/multipartjobtest.cpp b/messagecomposer/tests/multipartjobtest.cpp index 947727a96..413fe74ec 100644 --- a/messagecomposer/tests/multipartjobtest.cpp +++ b/messagecomposer/tests/multipartjobtest.cpp @@ -1,104 +1,105 @@ /* Copyright (c) 2009 Constantin Berzan 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. */ #include "multipartjobtest.h" #include #include #include using namespace KMime; #include -#include +#include +#include #include using namespace MessageComposer; QTEST_KDEMAIN( MultipartJobTest, NoGUI ) void MultipartJobTest::testMultipartMixed() { Composer *composer = new Composer; MultipartJob *mjob = new MultipartJob( composer ); mjob->setMultipartSubtype( "mixed" ); QByteArray data1( "one" ); QByteArray data2( "two" ); QByteArray type1( "text/plain" ); QByteArray type2( "application/x-mors-ontologica" ); { - ContentJob *cjob = new ContentJob( mjob ); + SinglepartJob *cjob = new SinglepartJob( mjob ); cjob->setData( data1 ); cjob->contentType()->setMimeType( type1 ); } { - ContentJob *cjob = new ContentJob( mjob ); + SinglepartJob *cjob = new SinglepartJob( mjob ); cjob->setData( data2 ); cjob->contentType()->setMimeType( type2 ); } QVERIFY( mjob->exec() ); Content *result = mjob->content(); result->assemble(); kDebug() << result->encodedContent(); QVERIFY( result->contentType( false ) ); QCOMPARE( result->contentType()->mimeType(), QByteArray( "multipart/mixed" ) ); QCOMPARE( result->contents().count(), 2 ); { Content *c = result->contents().at( 0 ); QCOMPARE( c->body(), data1 ); QVERIFY( c->contentType( false ) ); QCOMPARE( c->contentType()->mimeType(), type1 ); } { Content *c = result->contents().at( 1 ); QCOMPARE( c->body(), data2 ); QVERIFY( c->contentType( false ) ); QCOMPARE( c->contentType()->mimeType(), type2 ); } } void MultipartJobTest::test8BitPropagation() { // If a subpart is 8bit, its parent must be 8bit too. Composer *composer = new Composer; - composer->behaviour().enableAction( Behaviour::EightBitTransport ); + composer->globalPart()->set8BitAllowed( true ); MultipartJob *mjob = new MultipartJob( composer ); mjob->setMultipartSubtype( "mixed" ); MultipartJob *mjob2 = new MultipartJob( mjob ); mjob2->setMultipartSubtype( "mixed" ); - ContentJob *cjob = new ContentJob( mjob2 ); + SinglepartJob *cjob = new SinglepartJob( mjob2 ); QByteArray data( "time is so short and I'm sure there must be something more" ); cjob->setData( data ); cjob->contentTransferEncoding()->setEncoding( Headers::CE8Bit ); QVERIFY( mjob->exec() ); Content *content = mjob->content(); content->assemble(); kDebug() << content->encodedContent(); QVERIFY( content->contentTransferEncoding( false ) ); QCOMPARE( content->contentTransferEncoding()->encoding(), Headers::CE8Bit ); } #include "multipartjobtest.moc" diff --git a/messagecomposer/tests/qtest_messagecomposer.h b/messagecomposer/tests/qtest_messagecomposer.h new file mode 100644 index 000000000..f791bc651 --- /dev/null +++ b/messagecomposer/tests/qtest_messagecomposer.h @@ -0,0 +1,33 @@ +/* + Copyright (C) 2009 Constantin Berzan + + Based on Akonadi code by: + Copyright (C) 2009 Volker Krause + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License version 2 as published by the Free Software Foundation. + + 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. +*/ + +#ifndef QTEST_MESSAGECOMPOSER_H +#define QTEST_MESSAGECOMPOSER_H + +/** + * Runs a MessageComposer::JobBase synchronously and aborts if the job failed. + * Similar to QVERIFY( job->exec() ) but includes the job error message + * in the output in case of a failure. + */ +#define VERIFYEXEC( job ) \ + QVERIFY2( job->exec(), job->errorString().toUtf8().constData() ) + +#endif diff --git a/messagecomposer/tests/contentjobtest.cpp b/messagecomposer/tests/singlepartjobtest.cpp similarity index 68% rename from messagecomposer/tests/contentjobtest.cpp rename to messagecomposer/tests/singlepartjobtest.cpp index 63a469beb..e98ade85b 100644 --- a/messagecomposer/tests/contentjobtest.cpp +++ b/messagecomposer/tests/singlepartjobtest.cpp @@ -1,139 +1,172 @@ /* Copyright (c) 2009 Constantin Berzan 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. */ -#include "contentjobtest.h" +#include "singlepartjobtest.h" #include #include #include using namespace KMime; #include -#include +#include +#include using namespace MessageComposer; -QTEST_KDEMAIN( ContentJobTest, NoGUI ) +QTEST_KDEMAIN( SinglepartJobTest, NoGUI ) -void ContentJobTest::testContent() +void SinglepartJobTest::testContent() { Composer *composer = new Composer; - ContentJob *cjob = new ContentJob( composer ); + SinglepartJob *cjob = new SinglepartJob( composer ); QByteArray data( "birds came flying from the underground" ); cjob->setData( data ); QVERIFY( cjob->exec() ); Content *result = cjob->content(); result->assemble(); kDebug() << result->encodedContent(); QCOMPARE( result->body(), data ); QVERIFY( result->contentDisposition( false ) == 0 ); // Not created unless demanded. QVERIFY( result->contentType( false ) == 0 ); // Not created unless demanded. QVERIFY( result->contentTransferEncoding( false ) ); // KMime gives it a default one (7bit). } -void ContentJobTest::testContentDisposition() +void SinglepartJobTest::testContentDisposition() { Composer *composer = new Composer; - ContentJob *cjob = new ContentJob( composer ); + SinglepartJob *cjob = new SinglepartJob( composer ); QByteArray data( "birds came flying from the underground" ); cjob->setData( data ); QString filename = QString::fromUtf8( "test_ăîşţâ.txt" ); cjob->contentDisposition()->setDisposition( Headers::CDattachment ); cjob->contentDisposition()->setFilename( filename ); QVERIFY( cjob->exec() ); Content *result = cjob->content(); result->assemble(); kDebug() << result->encodedContent(); QCOMPARE( result->body(), data ); QVERIFY( result->contentDisposition( false ) ); QCOMPARE( result->contentDisposition()->disposition(), Headers::CDattachment ); QCOMPARE( result->contentDisposition()->filename(), filename ); } -void ContentJobTest::testContentType() +void SinglepartJobTest::testContentID() { Composer *composer = new Composer; - ContentJob *cjob = new ContentJob( composer ); + SinglepartJob *cjob = new SinglepartJob( composer ); + QByteArray data( "birds came flying from the underground" ); + QByteArray id( "play@cold" ); + cjob->setData( data ); + cjob->contentID()->setIdentifier( id ); + QVERIFY( cjob->exec() ); + Content *result = cjob->content(); + result->assemble(); + kDebug() << result->encodedContent(); + QCOMPARE( result->body(), data ); + QVERIFY( result->header() ); + QCOMPARE( result->header()->identifier(), id ); +} + +void SinglepartJobTest::testContentType() +{ + Composer *composer = new Composer; + SinglepartJob *cjob = new SinglepartJob( composer ); QByteArray data( "birds came flying from the underground" ); cjob->setData( data ); QByteArray mimeType( "text/plain" ); QByteArray charset( "utf-8" ); cjob->contentType()->setMimeType( mimeType ); cjob->contentType()->setCharset( charset ); QVERIFY( cjob->exec() ); Content *result = cjob->content(); result->assemble(); kDebug() << result->encodedContent(); QCOMPARE( result->body(), data ); QVERIFY( result->contentType( false ) ); QCOMPARE( result->contentType()->mimeType(), mimeType ); QCOMPARE( result->contentType()->charset(), charset ); } -void ContentJobTest::testContentTransferEncoding() +void SinglepartJobTest::testContentTransferEncoding() { Composer *composer = new Composer; - QVERIFY( !composer->behaviour().isActionEnabled( Behaviour::EightBitTransport ) ); - composer->behaviour().enableAction( Behaviour::UseFallbackCharset ); + QVERIFY( !composer->globalPart()->is8BitAllowed() ); + composer->globalPart()->setFallbackCharsetEnabled( true ); // 7bit if possible. { - ContentJob *cjob = new ContentJob( composer ); + SinglepartJob *cjob = new SinglepartJob( composer ); QByteArray data( "and the sun will set for you..." ); cjob->setData( data ); QVERIFY( cjob->exec() ); Content *result = cjob->content(); result->assemble(); kDebug() << result->encodedContent(); QVERIFY( result->contentTransferEncoding( false ) ); QCOMPARE( result->contentTransferEncoding()->encoding(), Headers::CE7Bit ); QCOMPARE( result->body(), data ); } // quoted-printable if text doesn't fit in 7bit. { - ContentJob *cjob = new ContentJob( composer ); + SinglepartJob *cjob = new SinglepartJob( composer ); QByteArray data( "some long text to make qupr more compact than base64 [ăîşţâ]" ); // utf-8 cjob->setData( data ); QVERIFY( cjob->exec() ); Content *result = cjob->content(); result->assemble(); kDebug() << result->encodedContent(); QVERIFY( result->contentTransferEncoding( false ) ); QCOMPARE( result->contentTransferEncoding()->encoding(), Headers::CEquPr ); QCOMPARE( result->body(), data ); } // base64 if it's shorter than quoted-printable { - ContentJob *cjob = new ContentJob( composer ); + SinglepartJob *cjob = new SinglepartJob( composer ); QByteArray data( "[ăîşţâ]" ); // utf-8 cjob->setData( data ); QVERIFY( cjob->exec() ); QVERIFY( cjob->exec() ); Content *result = cjob->content(); result->assemble(); kDebug() << result->encodedContent(); QVERIFY( result->contentTransferEncoding( false ) ); QCOMPARE( result->contentTransferEncoding()->encoding(), Headers::CEbase64 ); QCOMPARE( result->body(), data ); } + + // 8bit if asked for and allowed. + { + composer->globalPart()->set8BitAllowed( true ); + QByteArray data( "[ăîşţâ]" ); // utf-8 + SinglepartJob *cjob = new SinglepartJob( composer ); + cjob->setData( data ); + QVERIFY( cjob->exec() ); + Content *result = cjob->content(); + result->assemble(); + kDebug() << result->encodedContent(); + QVERIFY( result->contentTransferEncoding( false ) ); + QCOMPARE( result->contentTransferEncoding()->encoding(), Headers::CE8Bit ); + QCOMPARE( result->body(), data ); + } } -#include "contentjobtest.moc" +#include "singlepartjobtest.moc" diff --git a/messagecomposer/tests/contentjobtest.h b/messagecomposer/tests/singlepartjobtest.h similarity index 89% rename from messagecomposer/tests/contentjobtest.h rename to messagecomposer/tests/singlepartjobtest.h index bcc1f43cb..5198e3616 100644 --- a/messagecomposer/tests/contentjobtest.h +++ b/messagecomposer/tests/singlepartjobtest.h @@ -1,35 +1,36 @@ /* Copyright (c) 2009 Constantin Berzan 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. */ -#ifndef CONTENTJOBTEST_H -#define CONTENTJOBTEST_H +#ifndef SINGLEPARTJOBTEST_H +#define SINGLEPARTJOBTEST_H #include -class ContentJobTest : public QObject +class SinglepartJobTest : public QObject { Q_OBJECT private Q_SLOTS: void testContent(); void testContentDisposition(); + void testContentID(); void testContentType(); void testContentTransferEncoding(); }; #endif diff --git a/messagecomposer/tests/utiltest.cpp b/messagecomposer/tests/utiltest.cpp new file mode 100644 index 000000000..2e01df393 --- /dev/null +++ b/messagecomposer/tests/utiltest.cpp @@ -0,0 +1,67 @@ +/* + Copyright (c) 2009 Constantin Berzan + + 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. +*/ + +#include "utiltest.h" + +#include + +#include +using namespace MessageComposer; + +QTEST_KDEMAIN( UtilTest, NoGUI ) + +void UtilTest::testSelectCharset() +{ + // Pick a charset that actually works. + { + QString text = QString::fromUtf8( "text 123 ăîşţâ" ); + QList charsets; + charsets << "us-ascii"; + charsets << "iso-8859-1"; + charsets << "iso-8859-2"; // This one works. + QByteArray choice = selectCharset( charsets, text ); + QCOMPARE( choice, QByteArray( "iso-8859-2" ) ); + } + + // Pick as simple a charset as possible. + { + QString text = QString::fromUtf8( "plain English text" ); + QList charsets; + charsets << "us-ascii"; // This one works. + charsets << "iso-8859-1"; + charsets << "utf-8"; + QByteArray choice = selectCharset( charsets, text ); + QCOMPARE( choice, QByteArray( "us-ascii" ) ); + } + + // Return empty charset if none works. + { + QString text = QString::fromUtf8( "text 123 ăîşţâ" ); + QList charsets; + QByteArray choice = selectCharset( charsets, text ); + QVERIFY( choice.isEmpty() ); + charsets << "us-ascii"; + charsets << "iso-8859-1"; + choice = selectCharset( charsets, text ); + QVERIFY( choice.isEmpty() ); + } + +} + +#include "utiltest.moc" diff --git a/messagecomposer/tests/behaviourtest.h b/messagecomposer/tests/utiltest.h similarity index 89% rename from messagecomposer/tests/behaviourtest.h rename to messagecomposer/tests/utiltest.h index 2317b3f51..2bcc0898a 100644 --- a/messagecomposer/tests/behaviourtest.h +++ b/messagecomposer/tests/utiltest.h @@ -1,32 +1,32 @@ /* Copyright (c) 2009 Constantin Berzan 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. */ -#ifndef BEHAVIOURTEST_H -#define BEHAVIOURTEST_H +#ifndef UTILTEST_H +#define UTILTEST_H #include -class BehaviourTest : public QObject +class UtilTest : public QObject { Q_OBJECT private Q_SLOTS: - void testApi(); + void testSelectCharset(); }; #endif diff --git a/messagecomposer/textpart.cpp b/messagecomposer/textpart.cpp index 06cf2946f..ea1f53e43 100644 --- a/messagecomposer/textpart.cpp +++ b/messagecomposer/textpart.cpp @@ -1,92 +1,119 @@ /* Copyright (c) 2009 Constantin Berzan 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. */ #include "textpart.h" +using namespace KPIMTextEdit; using namespace MessageComposer; class TextPart::Private { public: + bool wordWrappingEnabled; + bool warnBadCharset; QString cleanPlainText; QString wrappedPlainText; QString cleanHtml; - QList charsets; - - // TODO related images + ImageList embeddedImages; }; TextPart::TextPart( QObject *parent ) : MessagePart( parent ) , d( new Private ) { + d->wordWrappingEnabled = true; + d->warnBadCharset = true; } TextPart::~TextPart() { delete d; } -QList TextPart::charsets() const +bool TextPart::isWordWrappingEnabled() const +{ + return d->wordWrappingEnabled; +} + +void TextPart::setWordWrappingEnabled( bool enabled ) { - return d->charsets; + d->wordWrappingEnabled = enabled; } -void TextPart::setCharsets( const QList &charsets ) +bool TextPart::warnBadCharset() const { - d->charsets = charsets; + return d->warnBadCharset; +} + +void TextPart::setWarnBadCharset( bool warn ) +{ + d->warnBadCharset = warn; } QString TextPart::cleanPlainText() const { return d->cleanPlainText; } void TextPart::setCleanPlainText( const QString &text ) { d->cleanPlainText = text; } QString TextPart::wrappedPlainText() const { return d->wrappedPlainText; } void TextPart::setWrappedPlainText( const QString &text ) { d->wrappedPlainText = text; } bool TextPart::isHtmlUsed() const { - // TODO - return false; + return !d->cleanHtml.isEmpty(); } QString TextPart::cleanHtml() const { return d->cleanHtml; } void TextPart::setCleanHtml( const QString &text ) { d->cleanHtml = text; } +bool TextPart::hasEmbeddedImages() const +{ + return !d->embeddedImages.isEmpty(); +} + +ImageList TextPart::embeddedImages() const +{ + return d->embeddedImages; +} + +void TextPart::setEmbeddedImages( const ImageList &images ) +{ + d->embeddedImages = images; +} + #include "textpart.moc" diff --git a/messagecomposer/textpart.h b/messagecomposer/textpart.h index 09c5e7d5a..e104256d6 100644 --- a/messagecomposer/textpart.h +++ b/messagecomposer/textpart.h @@ -1,59 +1,67 @@ /* Copyright (c) 2009 Constantin Berzan 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. */ #ifndef MESSAGECOMPOSER_TEXTPART_H #define MESSAGECOMPOSER_TEXTPART_H #include #include "messagecomposer_export.h" #include "messagepart.h" +#include + namespace MessageComposer { -/** setOverrideTransferEncoding for a textPart means setting it for the plain text part, - and possibly for the html part. */ class MESSAGECOMPOSER_EXPORT TextPart : public MessagePart { Q_OBJECT public: explicit TextPart( QObject *parent = 0 ); virtual ~TextPart(); - QList charsets() const; - void setCharsets( const QList &charsets ); + // default true + bool isWordWrappingEnabled() const; + void setWordWrappingEnabled( bool enabled ); + // default true + bool warnBadCharset() const; + void setWarnBadCharset( bool warn ); QString cleanPlainText() const; void setCleanPlainText( const QString &text ); QString wrappedPlainText() const; void setWrappedPlainText( const QString &text ); bool isHtmlUsed() const; QString cleanHtml() const; void setCleanHtml( const QString &text ); + bool hasEmbeddedImages() const; + KPIMTextEdit::ImageList embeddedImages() const; + void setEmbeddedImages( const KPIMTextEdit::ImageList &images ); + private: class Private; Private *const d; }; } // namespace MessageComposer #endif // MESSAGECOMPOSER_TEXTPART_H diff --git a/messagecomposer/util.cpp b/messagecomposer/util.cpp index 41d5fd713..c655bbb98 100644 --- a/messagecomposer/util.cpp +++ b/messagecomposer/util.cpp @@ -1,37 +1,103 @@ /* Copyright (c) 2009 Constantin Berzan + Parts based on KMail code by: + Copyright 2009 Thomas McGuire + 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. */ #include "util.h" +#include + +#include +#include + +#include +#include +#include + using namespace KMime; using namespace MessageComposer; -QString MessageComposer::nameForEncoding( Headers::contentEncoding enc ) +QByteArray MessageComposer::selectCharset( const QList &charsets, const QString &text ) { - switch( enc ) { - case Headers::CE7Bit: return QString::fromLatin1( "7bit" ); - case Headers::CE8Bit: return QString::fromLatin1( "8bit" ); - case Headers::CEquPr: return QString::fromLatin1( "quoted-printable" ); - case Headers::CEbase64: return QString::fromLatin1( "base64" ); - case Headers::CEuuenc: return QString::fromLatin1( "uuencode" ); - case Headers::CEbinary: return QString::fromLatin1( "binary" ); - default: return QString::fromLatin1( "unknown" ); + foreach( const QByteArray &name, charsets ) { + // We use KCharsets::codecForName() instead of QTextCodec::codecForName() here, because + // the former knows us-ascii is latin1. + QTextCodec *codec = KGlobal::charsets()->codecForName( QString::fromLatin1( name ) ); + if( !codec ) { + kWarning() << "Could not get text codec for charset" << name; + continue; + } + if( codec->canEncode( text ) ) { + // Special check for us-ascii (needed because us-ascii is not exactly latin1). + if( name == "us-ascii" && !isUsAscii( text ) ) { + continue; + } + kDebug() << "Chosen charset" << name; + return name; + } } + kDebug() << "No appropriate charset found."; + return QByteArray(); +} + +QList MessageComposer::encodingsForData( const QByteArray &data ) +{ + QList allowed; + CharFreq cf( data ); + + switch ( cf.type() ) { + case CharFreq::SevenBitText: + allowed << Headers::CE7Bit; + case CharFreq::EightBitText: + allowed << Headers::CE8Bit; + case CharFreq::SevenBitData: + if ( cf.printableRatio() > 5.0/6.0 ) { + // let n the length of data and p the number of printable chars. + // Then base64 \approx 4n/3; qp \approx p + 3(n-p) + // => qp < base64 iff p > 5n/6. + allowed << Headers::CEquPr; + allowed << Headers::CEbase64; + } else { + allowed << Headers::CEbase64; + allowed << Headers::CEquPr; + } + break; + case CharFreq::EightBitData: + allowed << Headers::CEbase64; + break; + case CharFreq::None: + default: + Q_ASSERT( false ); + } + + return allowed; +} + +qint64 MessageComposer::sizeWithEncoding( const QByteArray &data, + Headers::contentEncoding encoding ) +{ + Content *c = new Content; + c->setBody( data ); + c->contentTransferEncoding()->setEncoding( encoding ); + int size = c->size(); + delete c; + return size; } diff --git a/messagecomposer/util.h b/messagecomposer/util.h index d966e1bd1..b144f8d06 100644 --- a/messagecomposer/util.h +++ b/messagecomposer/util.h @@ -1,37 +1,45 @@ /* Copyright (c) 2009 Constantin Berzan 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. */ #ifndef MESSAGECOMPOSER_UTIL_H #define MESSAGECOMPOSER_UTIL_H -//#include "messagecomposer_export.h" +#include "messagecomposer_export.h" #include #include namespace MessageComposer { -// TODO move to KMime? -// or move to ContentJob if we'll only need it there. -QString nameForEncoding( KMime::Headers::contentEncoding enc ); +// TODO should these be exported? +// They are used in the unit tests, but are they useful to the outside world? + +MESSAGECOMPOSER_EXPORT QByteArray selectCharset( const QList &charsets, + const QString &text ); + +MESSAGECOMPOSER_EXPORT QList encodingsForData( + const QByteArray &data ); + +MESSAGECOMPOSER_EXPORT qint64 sizeWithEncoding( const QByteArray &data, + KMime::Headers::contentEncoding encoding ); } #endif