Fix wrong connect
[kdepim.git] / korgac / mailclient.cpp
blobd7ca389e156771aad238a24df0ac4df8ca1bd70d
1 /*
2 Copyright (c) 1998 Barry D Benowitz <b.benowitz@telesciences.com>
3 Copyright (c) 2001 Cornelius Schumacher <schumacher@kde.org>
4 Copyright (c) 2009 Allen Winter <winter@kde.org>
6 This program is free software; you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation; either version 2 of the License, or
9 (at your option) any later version.
11 This program is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 GNU General Public License for more details.
16 You should have received a copy of the GNU General Public License along
17 with this program; if not, write to the Free Software Foundation, Inc.,
18 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
20 As a special exception, permission is given to link this program
21 with any edition of Qt, and distribute the resulting executable,
22 without including the source code for Qt in the source distribution.
25 #include <config-enterprise.h>
27 #include "mailclient.h"
28 #include "kdepim-version.h"
29 #include "koalarmclient_debug.h"
31 #include <AkonadiCore/Collection>
33 #include <KCalCore/Attendee>
34 #include <KCalCore/Incidence>
35 #include <KCalCore/IncidenceBase>
37 #include <KCalUtils/IncidenceFormatter>
39 #include <KMime/Message>
41 #include <KIdentityManagement/Identity>
43 #include <KEmailAddress>
45 #include <MailTransport/MessageQueueJob>
46 #include <MailTransport/Transport>
47 #include <MailTransport/TransportManager>
49 #include <KLocalizedString>
50 #include <KProtocolManager>
51 #include <KSystemTimeZone>
53 using namespace KOrg;
55 MailClient::MailClient() : QObject()
59 MailClient::~MailClient()
63 bool MailClient::mailAttendees(const KCalCore::IncidenceBase::Ptr &incidence,
64 const KIdentityManagement::Identity &identity,
65 bool bccMe, const QString &attachment,
66 const QString &mailTransport)
68 KCalCore::Attendee::List attendees = incidence->attendees();
69 if (attendees.isEmpty()) {
70 qCDebug(KOALARMCLIENT_LOG) << "There are no attendees to e-mail";
71 return false;
74 const QString from = incidence->organizer()->fullName();
75 const QString organizerEmail = incidence->organizer()->email();
77 QStringList toList;
78 QStringList ccList;
79 const int numberOfAttendees(attendees.count());
80 for (int i = 0; i < numberOfAttendees; ++i) {
81 KCalCore::Attendee::Ptr a = attendees.at(i);
83 const QString email = a->email();
84 if (email.isEmpty()) {
85 continue;
88 // In case we (as one of our identities) are the organizer we are sending
89 // this mail. We could also have added ourselves as an attendee, in which
90 // case we don't want to send ourselves a notification mail.
91 if (organizerEmail == email) {
92 continue;
95 // Build a nice address for this attendee including the CN.
96 QString tname, temail;
97 const QString username = KEmailAddress::quoteNameIfNecessary(a->name());
98 // ignore the return value from extractEmailAddressAndName() because
99 // it will always be false since tusername does not contain "@domain".
100 KEmailAddress::extractEmailAddressAndName(username, temail/*byref*/, tname/*byref*/);
101 tname += QStringLiteral(" <") + email + QLatin1Char('>');
103 // Optional Participants and Non-Participants are copied on the email
104 if (a->role() == KCalCore::Attendee::OptParticipant ||
105 a->role() == KCalCore::Attendee::NonParticipant) {
106 ccList << tname;
107 } else {
108 toList << tname;
111 if (toList.isEmpty() && ccList.isEmpty()) {
112 // Not really to be called a groupware meeting, eh
113 qCDebug(KOALARMCLIENT_LOG) << "There are really no attendees to e-mail";
114 return false;
116 QString to;
117 if (!toList.isEmpty()) {
118 to = toList.join(QStringLiteral(", "));
120 QString cc;
121 if (!ccList.isEmpty()) {
122 cc = ccList.join(QStringLiteral(", "));
125 QString subject;
126 if (incidence->type() != KCalCore::Incidence::TypeFreeBusy) {
127 KCalCore::Incidence::Ptr inc = incidence.staticCast<KCalCore::Incidence>();
128 subject = inc->summary();
129 } else {
130 subject = i18n("Free Busy Object");
133 const QString body =
134 KCalUtils::IncidenceFormatter::mailBodyStr(incidence, KSystemTimeZones::local());
136 return send(identity, from, to, cc, subject, body, false,
137 bccMe, attachment, mailTransport);
140 bool MailClient::mailOrganizer(const KCalCore::IncidenceBase::Ptr &incidence,
141 const KIdentityManagement::Identity &identity,
142 const QString &from, bool bccMe,
143 const QString &attachment,
144 const QString &sub, const QString &mailTransport)
146 const QString to = incidence->organizer()->fullName();
147 QString subject = sub;
149 if (incidence->type() != KCalCore::Incidence::TypeFreeBusy) {
150 KCalCore::Incidence::Ptr inc = incidence.staticCast<KCalCore::Incidence>();
151 if (subject.isEmpty()) {
152 subject = inc->summary();
154 } else {
155 subject = i18n("Free Busy Message");
158 const QString body = KCalUtils::IncidenceFormatter::mailBodyStr(incidence, KSystemTimeZones::local());
160 return send(identity, from, to, QString(), subject, body, false,
161 bccMe, attachment, mailTransport);
164 bool MailClient::mailTo(const KCalCore::IncidenceBase::Ptr &incidence,
165 const KIdentityManagement::Identity &identity,
166 const QString &from, bool bccMe,
167 const QString &recipients, const QString &attachment,
168 const QString &mailTransport)
170 QString subject;
172 if (incidence->type() != KCalCore::Incidence::TypeFreeBusy) {
173 KCalCore::Incidence::Ptr inc = incidence.staticCast<KCalCore::Incidence>() ;
174 subject = inc->summary();
175 } else {
176 subject = i18n("Free Busy Message");
178 const QString body =
179 KCalUtils::IncidenceFormatter::mailBodyStr(incidence, KSystemTimeZones::local());
181 return send(identity, from, recipients, QString(), subject, body, false,
182 bccMe, attachment, mailTransport);
185 QStringList extractEmailAndNormalize(const QString &email)
187 const QStringList splittedEmail = KEmailAddress::splitAddressList(email);
188 QStringList normalizedEmail;
189 normalizedEmail.reserve(splittedEmail.count());
190 Q_FOREACH (const QString &email, splittedEmail) {
191 const QString str = KEmailAddress::extractEmailAddress(KEmailAddress::normalizeAddressesAndEncodeIdn(email));
192 normalizedEmail << str;
194 return normalizedEmail;
197 bool MailClient::send(const KIdentityManagement::Identity &identity,
198 const QString &from, const QString &_to,
199 const QString &cc, const QString &subject,
200 const QString &body, bool hidden, bool bccMe,
201 const QString &attachment, const QString &mailTransport)
203 Q_UNUSED(hidden);
205 if (!MailTransport::TransportManager::self()->showTransportCreationDialog(
206 0, MailTransport::TransportManager::IfNoTransportExists)) {
207 return false;
210 // We must have a recipients list for most MUAs. Thus, if the 'to' list
211 // is empty simply use the 'from' address as the recipient.
212 QString to = _to;
213 if (to.isEmpty()) {
214 to = from;
216 qCDebug(KOALARMCLIENT_LOG) << "\nFrom:" << from
217 << "\nTo:" << to
218 << "\nCC:" << cc
219 << "\nSubject:" << subject << "\nBody: \n" << body
220 << "\nAttachment:\n" << attachment
221 << "\nmailTransport: " << mailTransport;
223 QTime timer;
224 timer.start();
226 MailTransport::Transport *transport =
227 MailTransport::TransportManager::self()->transportByName(mailTransport);
229 if (!transport) {
230 transport = MailTransport::TransportManager::self()->transportById(MailTransport::TransportManager::self()->defaultTransportId(), false);
233 if (!transport) {
234 // TODO: we need better error handling. Currently korganizer says "Error sending invitation".
235 // Using a boolean for errors isn't granular enough.
236 qCCritical(KOALARMCLIENT_LOG) << "Error fetching transport; mailTransport"
237 << mailTransport << MailTransport::TransportManager::self()->defaultTransportName();
238 return false;
241 const int transportId = transport->id();
243 // gather config values
244 KConfig config(QStringLiteral("kmail2rc"));
246 KConfigGroup configGroup(&config, QStringLiteral("Invitations"));
247 const bool outlookConformInvitation = configGroup.readEntry("LegacyBodyInvites",
248 #ifdef KDEPIM_ENTERPRISE_BUILD
249 true
250 #else
251 false
252 #endif
255 // Now build the message we like to send. The message KMime::Message::Ptr instance
256 // will be the root message that has 2 additional message. The body itself and
257 // the attached cal.ics calendar file.
258 KMime::Message::Ptr message = KMime::Message::Ptr(new KMime::Message);
259 message->contentTransferEncoding()->clear(); // 7Bit, decoded.
261 // Set the headers
262 message->userAgent()->fromUnicodeString(
263 KProtocolManager::userAgentForApplication(
264 QStringLiteral("KOrganizer"), QStringLiteral(KDEPIM_VERSION)), "utf-8");
265 message->from()->fromUnicodeString(from, "utf-8");
266 message->to()->fromUnicodeString(to, "utf-8");
267 message->cc()->fromUnicodeString(cc, "utf-8");
268 if (bccMe) {
269 message->bcc()->fromUnicodeString(from, "utf-8"); //from==me, right?
271 message->date()->setDateTime(QDateTime::currentDateTime());
272 message->subject()->fromUnicodeString(subject, "utf-8");
274 if (outlookConformInvitation) {
275 message->contentType()->setMimeType("text/calendar");
276 message->contentType()->setCharset("utf-8");
277 message->contentType()->setName(QStringLiteral("cal.ics"), "utf-8");
278 message->contentType()->setParameter(QStringLiteral("method"), QStringLiteral("request"));
280 if (!attachment.isEmpty()) {
281 KMime::Headers::ContentDisposition *disposition =
282 new KMime::Headers::ContentDisposition(message.get());
283 disposition->setDisposition(KMime::Headers::CDinline);
284 message->setHeader(disposition);
285 message->contentTransferEncoding()->setEncoding(KMime::Headers::CEquPr);
286 message->setBody(KMime::CRLFtoLF(attachment.toUtf8()));
288 } else {
289 // We need to set following 4 lines by hand else KMime::Content::addContent
290 // will create a new Content instance for us to attach the main message
291 // what we don't need cause we already have the main message instance where
292 // 2 additional messages are attached.
293 KMime::Headers::ContentType *ct = message->contentType();
294 ct->setMimeType("multipart/mixed");
295 ct->setBoundary(KMime::multiPartBoundary());
296 ct->setCategory(KMime::Headers::CCcontainer);
298 // Set the first multipart, the body message.
299 KMime::Content *bodyMessage = new KMime::Content;
300 KMime::Headers::ContentDisposition *bodyDisposition =
301 new KMime::Headers::ContentDisposition(bodyMessage);
302 bodyDisposition->setDisposition(KMime::Headers::CDinline);
303 bodyMessage->contentType()->setMimeType("text/plain");
304 bodyMessage->contentType()->setCharset("utf-8");
305 bodyMessage->contentTransferEncoding()->setEncoding(KMime::Headers::CEquPr);
306 bodyMessage->setBody(KMime::CRLFtoLF(body.toUtf8()));
307 message->addContent(bodyMessage);
309 // Set the sedcond multipart, the attachment.
310 if (!attachment.isEmpty()) {
311 KMime::Content *attachMessage = new KMime::Content;
312 KMime::Headers::ContentDisposition *attachDisposition =
313 new KMime::Headers::ContentDisposition(attachMessage);
314 attachDisposition->setDisposition(KMime::Headers::CDattachment);
315 attachMessage->contentType()->setMimeType("text/calendar");
316 attachMessage->contentType()->setCharset("utf-8");
317 attachMessage->contentType()->setName(QStringLiteral("cal.ics"), "utf-8");
318 attachMessage->contentType()->setParameter(QStringLiteral("method"),
319 QStringLiteral("request"));
320 attachMessage->setHeader(attachDisposition);
321 attachMessage->contentTransferEncoding()->setEncoding(KMime::Headers::CEquPr);
322 attachMessage->setBody(KMime::CRLFtoLF(attachment.toUtf8()));
323 message->addContent(attachMessage);
327 // Job done, attach the both multiparts and assemble the message.
328 message->assemble();
330 // Put the newly created item in the MessageQueueJob.
331 MailTransport::MessageQueueJob *qjob = new MailTransport::MessageQueueJob(this);
332 qjob->transportAttribute().setTransportId(transportId);
334 if (identity.disabledFcc()) {
335 qjob->sentBehaviourAttribute().setSentBehaviour(MailTransport::SentBehaviourAttribute::Delete);
336 } else {
337 const Akonadi::Collection sentCollection(identity.fcc().toLongLong());
338 if (sentCollection.isValid()) {
339 qjob->sentBehaviourAttribute().setSentBehaviour(MailTransport::SentBehaviourAttribute::MoveToCollection);
340 qjob->sentBehaviourAttribute().setMoveToCollection(sentCollection);
341 } else {
342 qjob->sentBehaviourAttribute().setSentBehaviour(
343 MailTransport::SentBehaviourAttribute::MoveToDefaultSentCollection);
347 if (transport && transport->specifySenderOverwriteAddress()) {
348 qjob->addressAttribute().setFrom(
349 KEmailAddress::extractEmailAddress(
350 KEmailAddress::normalizeAddressesAndEncodeIdn(transport->senderOverwriteAddress())));
351 } else {
352 qjob->addressAttribute().setFrom(
353 KEmailAddress::extractEmailAddress(
354 KEmailAddress::normalizeAddressesAndEncodeIdn(from)));
357 if (!to.isEmpty()) {
358 qjob->addressAttribute().setTo(extractEmailAndNormalize(to));
360 if (!cc.isEmpty()) {
361 qjob->addressAttribute().setCc(extractEmailAndNormalize(cc));
363 if (bccMe) {
364 qjob->addressAttribute().setBcc(extractEmailAndNormalize(from));
366 qjob->setMessage(message);
367 if (!qjob->exec()) {
368 qCDebug(KOALARMCLIENT_LOG) << "Error queuing message in outbox:" << qjob->errorText();
369 return false;
372 // Everything done successful now.
373 qCDebug(KOALARMCLIENT_LOG) << "Send mail finished. Time elapsed in ms:" << timer.elapsed();
374 return true;