mirror of
https://bitbucket.org/smil3y/kde-playground.git
synced 2025-02-24 10:52:52 +00:00
401 lines
16 KiB
C++
401 lines
16 KiB
C++
/*
|
|
Copyright (c) 1998 Barry D Benowitz <b.benowitz@telesciences.com>
|
|
Copyright (c) 2001 Cornelius Schumacher <schumacher@kde.org>
|
|
Copyright (c) 2009 Allen Winter <winter@kde.org>
|
|
|
|
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 "mailclient_p.h"
|
|
|
|
#include "akonadi/kdepimlibs-version.h"
|
|
|
|
#include <akonadi/collection.h>
|
|
|
|
#include <kcalcore/attendee.h>
|
|
#include <kcalcore/incidence.h>
|
|
#include <kcalcore/incidencebase.h>
|
|
#include <kcalutils/incidenceformatter.h>
|
|
#include <kmime/kmime_message.h>
|
|
#include <kpimidentities/identity.h>
|
|
#include <kpimutils/email.h>
|
|
|
|
#include <mailtransport/messagequeuejob.h>
|
|
#include <mailtransport/transport.h>
|
|
#include <mailtransport/transportmanager.h>
|
|
|
|
#include <KDebug>
|
|
#include <KLocalizedString>
|
|
#include <KJob>
|
|
#include <KProtocolManager>
|
|
#include <KSystemTimeZone>
|
|
|
|
using namespace Akonadi;
|
|
|
|
bool Akonadi::MailClient::sRunningUnitTests = false;
|
|
UnitTestResult::List MailClient::sUnitTestResults;
|
|
|
|
MailClient::MailClient(QObject *parent) : QObject(parent)
|
|
{
|
|
}
|
|
|
|
MailClient::~MailClient()
|
|
{
|
|
}
|
|
|
|
void MailClient::mailAttendees(const KCalCore::IncidenceBase::Ptr &incidence,
|
|
const KPIMIdentities::Identity &identity,
|
|
bool bccMe, const QString &attachment,
|
|
const QString &mailTransport)
|
|
{
|
|
Q_ASSERT(incidence);
|
|
KCalCore::Attendee::List attendees = incidence->attendees();
|
|
if (attendees.isEmpty()) {
|
|
kWarning() << "There are no attendees to e-mail";
|
|
emit finished(ResultNoAttendees, i18n("There are no attendees to e-mail"));
|
|
return;
|
|
}
|
|
|
|
const QString from = incidence->organizer()->fullName();
|
|
const QString organizerEmail = incidence->organizer()->email();
|
|
|
|
QStringList toList;
|
|
QStringList ccList;
|
|
const int numberOfAttendees = attendees.count();
|
|
for (int i=0; i<numberOfAttendees; ++i) {
|
|
KCalCore::Attendee::Ptr a = attendees.at(i);
|
|
|
|
const QString email = a->email();
|
|
if (email.isEmpty()) {
|
|
continue;
|
|
}
|
|
|
|
// In case we (as one of our identities) are the organizer we are sending
|
|
// this mail. We could also have added ourselves as an attendee, in which
|
|
// case we don't want to send ourselves a notification mail.
|
|
if (organizerEmail == email) {
|
|
continue;
|
|
}
|
|
|
|
// Build a nice address for this attendee including the CN.
|
|
QString tname, temail;
|
|
const QString username = KPIMUtils::quoteNameIfNecessary(a->name());
|
|
// ignore the return value from extractEmailAddressAndName() because
|
|
// it will always be false since tusername does not contain "@domain".
|
|
KPIMUtils::extractEmailAddressAndName(username, temail/*byref*/, tname/*byref*/);
|
|
tname += QLatin1String(" <") + email + QLatin1Char('>');
|
|
|
|
// Optional Participants and Non-Participants are copied on the email
|
|
if (a->role() == KCalCore::Attendee::OptParticipant ||
|
|
a->role() == KCalCore::Attendee::NonParticipant) {
|
|
ccList << tname;
|
|
} else {
|
|
toList << tname;
|
|
}
|
|
}
|
|
if (toList.isEmpty() && ccList.isEmpty()) {
|
|
// Not really to be called a groupware meeting, eh
|
|
kWarning() << "There are really no attendees to e-mail";
|
|
emit finished(ResultReallyNoAttendees, i18n("There are no attendees to e-mail"));
|
|
return;
|
|
}
|
|
QString to;
|
|
if (!toList.isEmpty()) {
|
|
to = toList.join(QLatin1String(", "));
|
|
}
|
|
QString cc;
|
|
if (!ccList.isEmpty()) {
|
|
cc = ccList.join(QLatin1String(", "));
|
|
}
|
|
|
|
QString subject;
|
|
if (incidence->type() != KCalCore::Incidence::TypeFreeBusy) {
|
|
KCalCore::Incidence::Ptr inc = incidence.staticCast<KCalCore::Incidence>();
|
|
subject = inc->summary();
|
|
} else {
|
|
subject = i18n("Free Busy Object");
|
|
}
|
|
|
|
const QString body = KCalUtils::IncidenceFormatter::mailBodyStr(incidence,
|
|
KSystemTimeZones::local());
|
|
|
|
send(identity, from, to, cc, subject, body, false, bccMe, attachment, mailTransport);
|
|
}
|
|
|
|
void MailClient::mailOrganizer(const KCalCore::IncidenceBase::Ptr &incidence,
|
|
const KPIMIdentities::Identity &identity,
|
|
const QString &from, bool bccMe,
|
|
const QString &attachment,
|
|
const QString &sub, const QString &mailTransport)
|
|
{
|
|
const QString to = incidence->organizer()->fullName();
|
|
QString subject = sub;
|
|
|
|
if (incidence->type() != KCalCore::Incidence::TypeFreeBusy) {
|
|
KCalCore::Incidence::Ptr inc = incidence.staticCast<KCalCore::Incidence>();
|
|
if (subject.isEmpty()) {
|
|
subject = inc->summary();
|
|
}
|
|
} else {
|
|
subject = i18n("Free Busy Message");
|
|
}
|
|
|
|
const QString body = KCalUtils::IncidenceFormatter::mailBodyStr(incidence,
|
|
KSystemTimeZones::local());
|
|
|
|
send(identity, from, to, QString(), subject, body, false, bccMe, attachment, mailTransport);
|
|
}
|
|
|
|
void MailClient::mailTo(const KCalCore::IncidenceBase::Ptr &incidence,
|
|
const KPIMIdentities::Identity &identity,
|
|
const QString &from, bool bccMe,
|
|
const QString &recipients, const QString &attachment,
|
|
const QString &mailTransport)
|
|
{
|
|
QString subject;
|
|
|
|
if (incidence->type() != KCalCore::Incidence::TypeFreeBusy) {
|
|
KCalCore::Incidence::Ptr inc = incidence.staticCast<KCalCore::Incidence>() ;
|
|
subject = inc->summary();
|
|
} else {
|
|
subject = i18n("Free Busy Message");
|
|
}
|
|
|
|
const QString body = KCalUtils::IncidenceFormatter::mailBodyStr(incidence,
|
|
KSystemTimeZones::local());
|
|
|
|
send(identity, from, recipients, QString(), subject, body, false,
|
|
bccMe, attachment, mailTransport);
|
|
}
|
|
|
|
static QStringList extractEmailAndNormalize(const QString &email)
|
|
{
|
|
const QStringList splittedEmail = KPIMUtils::splitAddressList(email);
|
|
QStringList normalizedEmail;
|
|
foreach(const QString &email, splittedEmail) {
|
|
const QString str = KPIMUtils::extractEmailAddress(KPIMUtils::normalizeAddressesAndEncodeIdn(email));
|
|
normalizedEmail << str;
|
|
}
|
|
return normalizedEmail;
|
|
}
|
|
|
|
void MailClient::send(const KPIMIdentities::Identity &identity,
|
|
const QString &from, const QString &_to,
|
|
const QString &cc, const QString &subject,
|
|
const QString &body, bool hidden, bool bccMe,
|
|
const QString &attachment, const QString &mailTransport)
|
|
{
|
|
Q_UNUSED(identity);
|
|
Q_UNUSED(hidden);
|
|
|
|
UnitTestResult unitTestResult;
|
|
|
|
if (!MailTransport::TransportManager::self()->showTransportCreationDialog(
|
|
0, MailTransport::TransportManager::IfNoTransportExists)) {
|
|
kError() << "Error while creating transport";
|
|
emit finished(ResultErrorCreatingTransport, i18n("Error while creating transport"));
|
|
return;
|
|
}
|
|
|
|
// We must have a recipients list for most MUAs. Thus, if the 'to' list
|
|
// is empty simply use the 'from' address as the recipient.
|
|
QString to = _to;
|
|
if (to.isEmpty()) {
|
|
to = from;
|
|
}
|
|
kDebug() << "\nFrom:" << from
|
|
<< "\nTo:" << to
|
|
<< "\nCC:" << cc
|
|
<< "\nSubject:" << subject << "\nBody: \n" << body
|
|
<< "\nAttachment:\n" << attachment
|
|
<< "\nmailTransport: " << mailTransport;
|
|
|
|
QTime timer;
|
|
timer.start();
|
|
|
|
MailTransport::Transport *transport =
|
|
MailTransport::TransportManager::self()->transportByName(mailTransport);
|
|
|
|
if (!transport) {
|
|
transport =
|
|
MailTransport::TransportManager::self()->transportByName(
|
|
MailTransport::TransportManager::self()->defaultTransportName());
|
|
}
|
|
|
|
if (!transport) {
|
|
kError() << "Error fetching transport; mailTransport"
|
|
<< mailTransport << MailTransport::TransportManager::self()->defaultTransportName();
|
|
emit finished(ResultErrorFetchingTransport,
|
|
i18n("Error fetching transport. Unable to send invitations"));
|
|
return;
|
|
}
|
|
|
|
const int transportId = transport->id();
|
|
|
|
// gather config values
|
|
KConfig config(QLatin1String("mailviewerrc"));
|
|
|
|
KConfigGroup configGroup(&config, QLatin1String("Invitations"));
|
|
const bool outlookConformInvitation = configGroup.readEntry("LegacyBodyInvites",
|
|
#ifdef KDEPIM_ENTERPRISE_BUILD
|
|
true
|
|
#else
|
|
false
|
|
#endif
|
|
);
|
|
|
|
// Now build the message we like to send. The message KMime::Message::Ptr instance
|
|
// will be the root message that has 2 additional message. The body itself and
|
|
// the attached cal.ics calendar file.
|
|
KMime::Message::Ptr message = KMime::Message::Ptr(new KMime::Message);
|
|
message->contentTransferEncoding()->clear(); // 7Bit, decoded.
|
|
|
|
// Set the headers
|
|
|
|
message->userAgent()->fromUnicodeString(
|
|
KProtocolManager::userAgentForApplication(
|
|
QLatin1String("KOrganizer"), QLatin1String(KDEPIMLIBS_VERSION)), "utf-8");
|
|
|
|
message->from()->fromUnicodeString(from, "utf-8");
|
|
message->to()->fromUnicodeString(to, "utf-8");
|
|
message->cc()->fromUnicodeString(cc, "utf-8");
|
|
if (bccMe) {
|
|
message->bcc()->fromUnicodeString(from, "utf-8"); //from==me, right?
|
|
}
|
|
message->date()->setDateTime(KDateTime::currentLocalDateTime());
|
|
message->subject()->fromUnicodeString(subject, "utf-8");
|
|
|
|
if (outlookConformInvitation) {
|
|
message->contentType()->setMimeType("text/calendar");
|
|
message->contentType()->setCharset("utf-8");
|
|
message->contentType()->setName(QLatin1String("cal.ics"), "utf-8");
|
|
message->contentType()->setParameter(QLatin1String("method"), QLatin1String("request"));
|
|
|
|
if (!attachment.isEmpty()) {
|
|
KMime::Headers::ContentDisposition *disposition =
|
|
new KMime::Headers::ContentDisposition(message.get());
|
|
disposition->setDisposition(KMime::Headers::CDinline);
|
|
message->setHeader(disposition);
|
|
message->contentTransferEncoding()->setEncoding(KMime::Headers::CEquPr);
|
|
message->setBody(KMime::CRLFtoLF(attachment.toUtf8()));
|
|
}
|
|
} else {
|
|
// We need to set following 4 lines by hand else KMime::Content::addContent
|
|
// will create a new Content instance for us to attach the main message
|
|
// what we don't need cause we already have the main message instance where
|
|
// 2 additional messages are attached.
|
|
KMime::Headers::ContentType *ct = message->contentType();
|
|
ct->setMimeType("multipart/mixed");
|
|
ct->setBoundary(KMime::multiPartBoundary());
|
|
ct->setCategory(KMime::Headers::CCcontainer);
|
|
|
|
// Set the first multipart, the body message.
|
|
KMime::Content *bodyMessage = new KMime::Content;
|
|
KMime::Headers::ContentDisposition *bodyDisposition =
|
|
new KMime::Headers::ContentDisposition(bodyMessage);
|
|
bodyDisposition->setDisposition(KMime::Headers::CDinline);
|
|
bodyMessage->contentType()->setMimeType("text/plain");
|
|
bodyMessage->contentType()->setCharset("utf-8");
|
|
bodyMessage->contentTransferEncoding()->setEncoding(KMime::Headers::CEquPr);
|
|
bodyMessage->setBody(KMime::CRLFtoLF(body.toUtf8()));
|
|
message->addContent(bodyMessage);
|
|
|
|
// Set the sedcond multipart, the attachment.
|
|
if (!attachment.isEmpty()) {
|
|
KMime::Content *attachMessage = new KMime::Content;
|
|
KMime::Headers::ContentDisposition *attachDisposition =
|
|
new KMime::Headers::ContentDisposition(attachMessage);
|
|
attachDisposition->setDisposition(KMime::Headers::CDattachment);
|
|
attachMessage->contentType()->setMimeType("text/calendar");
|
|
attachMessage->contentType()->setCharset("utf-8");
|
|
attachMessage->contentType()->setName(QLatin1String("cal.ics"), "utf-8");
|
|
attachMessage->contentType()->setParameter(QLatin1String("method"),
|
|
QLatin1String("request"));
|
|
attachMessage->setHeader(attachDisposition);
|
|
attachMessage->contentTransferEncoding()->setEncoding(KMime::Headers::CEquPr);
|
|
attachMessage->setBody(KMime::CRLFtoLF(attachment.toUtf8()));
|
|
message->addContent(attachMessage);
|
|
}
|
|
}
|
|
|
|
// Job done, attach the both multiparts and assemble the message.
|
|
message->assemble();
|
|
|
|
// Put the newly created item in the MessageQueueJob.
|
|
MailTransport::MessageQueueJob *qjob = new MailTransport::MessageQueueJob(this);
|
|
qjob->transportAttribute().setTransportId(transportId);
|
|
qjob->sentBehaviourAttribute().setSentBehaviour(
|
|
MailTransport::SentBehaviourAttribute::MoveToDefaultSentCollection);
|
|
|
|
const QString unormalizedFrom = (transport && transport->specifySenderOverwriteAddress()) ?
|
|
transport->senderOverwriteAddress() : from;
|
|
|
|
const QString normalizedFrom = KPIMUtils::extractEmailAddress(
|
|
KPIMUtils::normalizeAddressesAndEncodeIdn(unormalizedFrom));
|
|
|
|
const QString finalFrom = KPIMUtils::extractEmailAddress(normalizedFrom);
|
|
qjob->addressAttribute().setFrom(finalFrom);
|
|
|
|
QStringList toStringList;
|
|
if (!to.isEmpty()) {
|
|
toStringList = extractEmailAndNormalize(to);
|
|
qjob->addressAttribute().setTo(toStringList);
|
|
}
|
|
|
|
QStringList ccStringList;
|
|
if (!cc.isEmpty()) {
|
|
ccStringList = extractEmailAndNormalize(cc);
|
|
qjob->addressAttribute().setCc(ccStringList);
|
|
}
|
|
|
|
QStringList bccStringList;
|
|
if (bccMe) {
|
|
bccStringList = extractEmailAndNormalize(from);
|
|
qjob->addressAttribute().setBcc(bccStringList);
|
|
}
|
|
|
|
if (sRunningUnitTests) {
|
|
unitTestResult.message = message;
|
|
unitTestResult.from = finalFrom;
|
|
unitTestResult.to = toStringList;
|
|
unitTestResult.cc = ccStringList;
|
|
unitTestResult.bcc = bccStringList;
|
|
unitTestResult.transportId = transportId;
|
|
sUnitTestResults << unitTestResult;
|
|
qjob->deleteLater();
|
|
|
|
QMetaObject::invokeMethod(this, "finished", Qt::QueuedConnection,
|
|
Q_ARG(Akonadi::MailClient::Result, ResultSuccess),
|
|
Q_ARG(QString, QString()));
|
|
|
|
} else {
|
|
qjob->setMessage(message);
|
|
connect(qjob, SIGNAL(finished(KJob*)), SLOT(handleQueueJobFinished(KJob*)));
|
|
qjob->start();
|
|
}
|
|
}
|
|
|
|
void MailClient::handleQueueJobFinished(KJob *job)
|
|
{
|
|
if (job->error()) {
|
|
kError() << "Error queueing message:" << job->errorText();
|
|
emit finished(ResultQueueJobError, i18n("Error queuing message in outbox: %1",
|
|
job->errorText()));
|
|
} else {
|
|
kDebug() << "Mail queued";
|
|
emit finished(ResultSuccess, QString());
|
|
}
|
|
}
|