diff --git a/messagecomposer/autotests/composertest.cpp b/messagecomposer/autotests/composertest.cpp index 1c05ecf8..105ebdf4 100644 --- a/messagecomposer/autotests/composertest.cpp +++ b/messagecomposer/autotests/composertest.cpp @@ -1,164 +1,162 @@ /* Copyright (c) 2009 Constantin Berzan Copyright (c) 2009 Leo Franchi 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 "qtest_messagecomposer.h" #include #include #include using namespace KMime; #include #include #include #include using namespace MessageComposer; #include using MessageCore::AttachmentPart; QTEST_MAIN(ComposerTest) void ComposerTest::testAttachments() { Composer *composer = new Composer; fillComposerData(composer); AttachmentPart::Ptr attachment = AttachmentPart::Ptr(new AttachmentPart); attachment->setData("abc"); attachment->setMimeType("x-some/x-type"); composer->addAttachmentPart(attachment); QVERIFY(composer->exec()); QCOMPARE(composer->resultMessages().size(), 1); KMime::Message::Ptr message = composer->resultMessages().first(); - qDebug() << message->encodedContent(); delete composer; composer = Q_NULLPTR; // multipart/mixed { QVERIFY(message->contentType(false)); QCOMPARE(message->contentType()->mimeType(), QByteArray("multipart/mixed")); QCOMPARE(message->contents().count(), 2); // text/plain { Content *plain = message->contents().at(0); QVERIFY(plain->contentType(false)); QCOMPARE(plain->contentType()->mimeType(), QByteArray("text/plain")); } // x-some/x-type (attachment) { Content *plain = message->contents().at(1); QVERIFY(plain->contentType(false)); QCOMPARE(plain->contentType()->mimeType(), QByteArray("x-some/x-type")); } } } void ComposerTest::testAutoSave() { Composer *composer = new Composer; fillComposerData(composer); AttachmentPart::Ptr attachment = AttachmentPart::Ptr(new AttachmentPart); attachment->setData("abc"); attachment->setMimeType("x-some/x-type"); composer->addAttachmentPart(attachment); // This tests if autosave in crash mode works without invoking an event loop, since using an // event loop in the crash handler would be a pretty bad idea composer->setAutoSave(true); composer->start(); QVERIFY(composer->finished()); QCOMPARE(composer->resultMessages().size(), 1); delete composer; composer = Q_NULLPTR; } void ComposerTest::testNonAsciiHeaders() { Composer *composer = new Composer; fillComposerData(composer); const QString mailbox = QStringLiteral(" "); const QString fromDisplayName = QStringLiteral("Hellö"); const QString toDisplayName = QStringLiteral("æſłĸð"); const QString ccDisplayName = QStringLiteral("Вася"); const QString bccDisplayName = QStringLiteral("ĸłſðđøþĸµ»«„¢þµ¢”«ł„·ĸ”"); const QString replyToDisplayName = QStringLiteral("æĸſłð˝đВасяðæĸđ"); const QString from = fromDisplayName + mailbox; const QString to = toDisplayName + mailbox; const QString cc = ccDisplayName + mailbox; const QString bcc = bccDisplayName + mailbox; const QString replyto = replyToDisplayName + mailbox; composer->infoPart()->setFrom(from); composer->infoPart()->setTo(QStringList() << to); composer->infoPart()->setCc(QStringList() << cc); composer->infoPart()->setBcc(QStringList() << bcc); composer->infoPart()->setReplyTo(replyto); QVERIFY(composer->exec()); QCOMPARE(composer->resultMessages().size(), 1); const KMime::Message::Ptr message = composer->resultMessages().first(); - qDebug() << message->encodedContent(); message->assemble(); message->parse(); QCOMPARE(message->bcc(false)->displayNames().size(), 1); QCOMPARE(message->to(false)->displayNames().size(), 1); QCOMPARE(message->cc(false)->displayNames().size(), 1); QCOMPARE(message->from(false)->displayNames().size(), 1); QCOMPARE(message->replyTo(false)->displayNames().size(), 1); - QCOMPARE(message->from()->displayNames().first().toUtf8(), fromDisplayName.toUtf8()); - QCOMPARE(message->to()->displayNames().first().toUtf8(), toDisplayName.toUtf8()); - QCOMPARE(message->cc()->displayNames().first().toUtf8(), ccDisplayName.toUtf8()); - QCOMPARE(message->bcc()->displayNames().first().toUtf8(), bccDisplayName.toUtf8()); - QCOMPARE(message->replyTo()->displayNames().first().toUtf8(), replyToDisplayName.toUtf8()); + QCOMPARE(message->from()->displayNames().first(), fromDisplayName); + QCOMPARE(message->to()->displayNames().first(), toDisplayName); + QCOMPARE(message->cc()->displayNames().first(), ccDisplayName); + QCOMPARE(message->bcc()->displayNames().first(), bccDisplayName); + QCOMPARE(message->replyTo()->displayNames().first(), replyToDisplayName); delete composer; composer = Q_NULLPTR; } void ComposerTest::testBug271192() { const QString displayName = QStringLiteral("Интернет-компания example"); const QString mailbox = QStringLiteral("example@example.com"); Composer *composer = new Composer; fillComposerData(composer); composer->infoPart()->setTo(QStringList() << (displayName + QLatin1String(" <") + mailbox + QLatin1String(">"))); QVERIFY(composer->exec()); QCOMPARE(composer->resultMessages().size(), 1); const KMime::Message::Ptr message = composer->resultMessages().first(); QCOMPARE(message->to()->displayNames().size(), 1); QCOMPARE(message->to()->displayNames().first().toUtf8(), displayName.toUtf8()); delete composer; composer = Q_NULLPTR; } void ComposerTest::fillComposerData(Composer *composer) { composer->globalPart()->setFallbackCharsetEnabled(true); composer->infoPart()->setFrom(QStringLiteral("me@me.me")); composer->infoPart()->setTo(QStringList(QStringLiteral("you@you.you"))); composer->textPart()->setWrappedPlainText(QStringLiteral("All happy families are alike; each unhappy family is unhappy in its own way.")); } diff --git a/messagecomposer/src/job/skeletonmessagejob.cpp b/messagecomposer/src/job/skeletonmessagejob.cpp index 4fe41bc9..aa00458d 100644 --- a/messagecomposer/src/job/skeletonmessagejob.cpp +++ b/messagecomposer/src/job/skeletonmessagejob.cpp @@ -1,266 +1,281 @@ /* 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 "settings/messagecomposersettings.h" #include "job/skeletonmessagejob.h" #include "messagecomposer-version.h" #include "part/infopart.h" #include "part/globalpart.h" #include "job/jobbase_p.h" #include #include #include #include "messagecomposer_debug.h" #include #include #include using namespace MessageComposer; class MessageComposer::SkeletonMessageJobPrivate : public JobBasePrivate { public: SkeletonMessageJobPrivate(SkeletonMessageJob *qq) : JobBasePrivate(qq) , infoPart(Q_NULLPTR) , globalPart(Q_NULLPTR) , message(Q_NULLPTR) { } void doStart(); // slot InfoPart *infoPart; GlobalPart *globalPart; KMime::Message *message; Q_DECLARE_PUBLIC(SkeletonMessageJob) }; void SkeletonMessageJobPrivate::doStart() { Q_Q(SkeletonMessageJob); Q_ASSERT(infoPart); Q_ASSERT(message == 0); message = new KMime::Message; // From: { KMime::Headers::From *from = new KMime::Headers::From; KMime::Types::Mailbox address; address.fromUnicodeString(KEmailAddress::normalizeAddressesAndEncodeIdn(infoPart->from())); - from->addAddress(address); + from->fromUnicodeString(QString::fromLatin1(address.as7BitString("utf-8")), "utf-8"); message->setHeader(from); } // To: { KMime::Headers::To *to = new KMime::Headers::To; + QByteArray sTo; foreach (const QString &a, infoPart->to()) { KMime::Types::Mailbox address; address.fromUnicodeString(KEmailAddress::normalizeAddressesAndEncodeIdn(a)); - to->addAddress(address); + if (!sTo.isEmpty()) { + sTo.append(","); + } + sTo.append(address.as7BitString("utf-8")); } + to->fromUnicodeString(QString::fromLatin1(sTo),"utf-8"); message->setHeader(to); } // Reply To: if (!infoPart->replyTo().isEmpty()) { KMime::Headers::ReplyTo *replyTo = new KMime::Headers::ReplyTo; KMime::Types::Mailbox address; address.fromUnicodeString(KEmailAddress::normalizeAddressesAndEncodeIdn(infoPart->replyTo())); - replyTo->addAddress(address); + replyTo->fromUnicodeString(QString::fromLatin1(address.as7BitString("utf-8")), "utf-8"); message->setHeader(replyTo); } // Cc: { KMime::Headers::Cc *cc = new KMime::Headers::Cc; + QByteArray sCc; foreach (const QString &a, infoPart->cc()) { KMime::Types::Mailbox address; address.fromUnicodeString(KEmailAddress::normalizeAddressesAndEncodeIdn(a)); - cc->addAddress(address); + if (!sCc.isEmpty()) { + sCc.append(","); + } + sCc.append(address.as7BitString("utf-8")); } + cc->fromUnicodeString(QString::fromLatin1(sCc),"utf-8"); message->setHeader(cc); } // Bcc: { KMime::Headers::Bcc *bcc = new KMime::Headers::Bcc; + QByteArray sBcc; foreach (const QString &a, infoPart->bcc()) { KMime::Types::Mailbox address; address.fromUnicodeString(KEmailAddress::normalizeAddressesAndEncodeIdn(a)); - bcc->addAddress(address); + if (!sBcc.isEmpty()) { + sBcc.append(","); + } + sBcc.append(address.as7BitString("utf-8")); } + bcc->fromUnicodeString(QString::fromLatin1(sBcc),"utf-8"); message->setHeader(bcc); } // Subject: { KMime::Headers::Subject *subject = new KMime::Headers::Subject; subject->fromUnicodeString(infoPart->subject(), "utf-8"); // TODO should we be more specific about the charset? message->setHeader(subject); } // Date: { KMime::Headers::Date *date = new KMime::Headers::Date; date->setDateTime(QDateTime::currentDateTime()); message->setHeader(date); } // Fcc: if (!infoPart->fcc().isEmpty()) { KMime::Headers::Generic *header = new KMime::Headers::Generic("X-KMail-Fcc"); header->fromUnicodeString(infoPart->fcc(), "utf-8"); message->setHeader(header); } //Transport: if (infoPart->transportId() > -1) { KMime::Headers::Generic *header = new KMime::Headers::Generic("X-KMail-Transport"); header->fromUnicodeString(QString::number(infoPart->transportId()), "utf-8"); message->setHeader(header); } // Message-ID { KMime::Headers::MessageID *messageId = new KMime::Headers::MessageID(); QByteArray fqdn; if (MessageComposer::MessageComposerSettings::self()->useCustomMessageIdSuffix()) { fqdn = QUrl::toAce(MessageComposer::MessageComposerSettings::self()->customMsgIDSuffix()); } if (fqdn.isEmpty()) { fqdn = QUrl::toAce(QHostInfo::localHostName()); } if (fqdn.isEmpty()) { qCWarning(MESSAGECOMPOSER_LOG) << "Unable to generate a Message-ID, falling back to 'localhost.localdomain'."; fqdn = "local.domain"; } messageId->generate(fqdn); message->setHeader(messageId); } // Extras foreach (KMime::Headers::Base *extra, infoPart->extraHeaders()) { message->setHeader(extra); } // MDN { if (globalPart->MDNRequested()) { const QString addr = infoPart->replyTo().isEmpty() ? infoPart->from() : infoPart->replyTo(); KMime::Headers::Generic *mdn = new KMime::Headers::Generic("Disposition-Notification-To"); mdn->fromUnicodeString(addr, "utf-8"); message->setHeader(mdn); } } // User-Agent if (!infoPart->userAgent().isEmpty()) { QStringList extraInfo; extraInfo << QLatin1String(MESSAGELIB_GIT_REVISION_STRING) << QLatin1String(MESSAGELIB_GIT_LAST_CHANGE); KMime::Headers::UserAgent *ua = new KMime::Headers::UserAgent; ua->fromUnicodeString(KProtocolManager::userAgentForApplication(infoPart->userAgent(), QStringLiteral(MESSAGELIB_LIB_VERSION), extraInfo), "utf-8"); message->setHeader(ua); } // Urgent header if (infoPart->urgent()) { KMime::Headers::Generic *urg1 = new KMime::Headers::Generic("X-PRIORITY"); urg1->fromUnicodeString(QStringLiteral("2 (High)"), "utf-8"); KMime::Headers::Generic *urg2 = new KMime::Headers::Generic("Priority"); urg2->fromUnicodeString(QStringLiteral("urgent"), "utf-8"); message->setHeader(urg1); message->setHeader(urg2); } // In-Reply-To if (!infoPart->inReplyTo().isEmpty()) { KMime::Headers::InReplyTo *header = new KMime::Headers::InReplyTo; header->fromUnicodeString(infoPart->inReplyTo(), "utf-8"); message->setHeader(header); } // References if (!infoPart->references().isEmpty()) { KMime::Headers::References *header = new KMime::Headers::References; header->fromUnicodeString(infoPart->references(), "utf-8"); message->setHeader(header); } q->emitResult(); // Success. } SkeletonMessageJob::SkeletonMessageJob(InfoPart *infoPart, GlobalPart *globalPart, QObject *parent) : JobBase(*new SkeletonMessageJobPrivate(this), parent) { Q_D(SkeletonMessageJob); d->infoPart = infoPart; d->globalPart = globalPart; } SkeletonMessageJob::~SkeletonMessageJob() { } InfoPart *SkeletonMessageJob::infoPart() const { Q_D(const SkeletonMessageJob); return d->infoPart; } void SkeletonMessageJob::setInfoPart(InfoPart *part) { Q_D(SkeletonMessageJob); d->infoPart = part; } GlobalPart *SkeletonMessageJob::globalPart() const { Q_D(const SkeletonMessageJob); return d->globalPart; } void SkeletonMessageJob::setGlobalPart(GlobalPart *part) { Q_D(SkeletonMessageJob); d->globalPart = part; } KMime::Message *SkeletonMessageJob::message() const { Q_D(const SkeletonMessageJob); return d->message; } void SkeletonMessageJob::start() { Q_D(SkeletonMessageJob); d->doStart(); } #include "moc_skeletonmessagejob.cpp"