File indexing completed on 2025-02-16 04:50:26

0001 /*
0002 
0003     SPDX-FileCopyrightText: 2012 Christian Mollekopf <chrigi_1@fastmail.fm>
0004 
0005     SPDX-License-Identifier: LGPL-2.1-or-later
0006 */
0007 
0008 #include "imip.h"
0009 #include "pimkolab_debug.h"
0010 
0011 #include <KCalUtils/IncidenceFormatter>
0012 #include <KEmailAddress>
0013 #include <KMime/Message>
0014 
0015 /*
0016  * The code in here is copy paste work from kdepim/calendarsupport.
0017  *
0018  * We need to refactor the code there and move the relevant parts to kdepimlibs to make it reusable.
0019  *
0020  *
0021  */
0022 
0023 // From MailClient::send
0024 KMime::Message::Ptr createMessage(const QString &from,
0025                                   const QString &_to,
0026                                   const QString &cc,
0027                                   const QString &subject,
0028                                   const QString &body,
0029                                   bool hidden,
0030                                   bool bccMe,
0031                                   const QString &attachment /*, const QString &mailTransport */)
0032 {
0033     Q_UNUSED(hidden)
0034 
0035     const bool outlookConformInvitation = false;
0036     QString userAgent = QStringLiteral("libkolab");
0037 
0038     // We must have a recipients list for most MUAs. Thus, if the 'to' list
0039     // is empty simply use the 'from' address as the recipient.
0040     QString to = _to;
0041     if (to.isEmpty()) {
0042         to = from;
0043     }
0044     qCDebug(PIMKOLAB_LOG) << "\nFrom:" << from << "\nTo:" << to << "\nCC:" << cc << "\nSubject:" << subject << "\nBody: \n"
0045                           << body << "\nAttachment:\n"
0046                           << attachment
0047         /*<< "\nmailTransport: " << mailTransport*/;
0048 
0049     // Now build the message we like to send. The message KMime::Message::Ptr instance
0050     // will be the root message that has 2 additional message. The body itself and
0051     // the attached cal.ics calendar file.
0052     KMime::Message::Ptr message = KMime::Message::Ptr(new KMime::Message);
0053     message->contentTransferEncoding()->clear(); // 7Bit, decoded.
0054 
0055     // Set the headers
0056     message->userAgent()->fromUnicodeString(userAgent, "utf-8");
0057     message->from()->fromUnicodeString(from, "utf-8");
0058     message->to()->fromUnicodeString(to, "utf-8");
0059     message->cc()->fromUnicodeString(cc, "utf-8");
0060     if (bccMe) {
0061         message->bcc()->fromUnicodeString(from, "utf-8"); // from==me, right?
0062     }
0063     message->date()->setDateTime(QDateTime::currentDateTime());
0064     message->subject()->fromUnicodeString(subject, "utf-8");
0065 
0066     if (outlookConformInvitation) {
0067         message->contentType()->setMimeType("text/calendar");
0068         message->contentType()->setCharset("utf-8");
0069         message->contentType()->setName(QStringLiteral("cal.ics"), "utf-8");
0070         message->contentType()->setParameter(QStringLiteral("method"), QStringLiteral("request"));
0071 
0072         if (!attachment.isEmpty()) {
0073             auto disposition = new KMime::Headers::ContentDisposition();
0074             disposition->setDisposition(KMime::Headers::CDinline);
0075             message->setHeader(disposition);
0076             message->contentTransferEncoding()->setEncoding(KMime::Headers::CEquPr);
0077             message->setBody(KMime::CRLFtoLF(attachment.toUtf8()));
0078         }
0079     } else {
0080         // We need to set following 4 lines by hand else KMime::Content::addContent
0081         // will create a new Content instance for us to attach the main message
0082         // what we don't need cause we already have the main message instance where
0083         // 2 additional messages are attached.
0084         KMime::Headers::ContentType *ct = message->contentType();
0085         ct->setMimeType("multipart/mixed");
0086         ct->setBoundary(KMime::multiPartBoundary());
0087 
0088         // Set the first multipart, the body message.
0089         auto bodyMessage = new KMime::Content;
0090         auto bodyDisposition = new KMime::Headers::ContentDisposition();
0091         bodyDisposition->setDisposition(KMime::Headers::CDinline);
0092         bodyMessage->contentType()->setMimeType("text/plain");
0093         bodyMessage->contentType()->setCharset("utf-8");
0094         bodyMessage->contentTransferEncoding()->setEncoding(KMime::Headers::CEquPr);
0095         bodyMessage->setBody(KMime::CRLFtoLF(body.toUtf8()));
0096         message->appendContent(bodyMessage);
0097 
0098         // Set the sedcond multipart, the attachment.
0099         if (!attachment.isEmpty()) {
0100             auto attachMessage = new KMime::Content;
0101             auto attachDisposition = new KMime::Headers::ContentDisposition();
0102             attachDisposition->setDisposition(KMime::Headers::CDattachment);
0103             attachMessage->contentType()->setMimeType("text/calendar");
0104             attachMessage->contentType()->setCharset("utf-8");
0105             attachMessage->contentType()->setName(QStringLiteral("cal.ics"), "utf-8");
0106             attachMessage->contentType()->setParameter(QStringLiteral("method"), QStringLiteral("request"));
0107             attachMessage->setHeader(attachDisposition);
0108             attachMessage->contentTransferEncoding()->setEncoding(KMime::Headers::CEquPr);
0109             attachMessage->setBody(KMime::CRLFtoLF(attachment.toUtf8()));
0110             message->appendContent(attachMessage);
0111         }
0112     }
0113 
0114     // Job done, attach the both multiparts and assemble the message.
0115     message->assemble();
0116     return message;
0117 }
0118 
0119 // From MailClient::mailAttendees
0120 QByteArray mailAttendees(const KCalendarCore::IncidenceBase::Ptr &incidence,
0121                          //                                 const KPIMIdentities::Identity &identity,
0122                          bool bccMe,
0123                          const QString &attachment
0124                          /*const QString &mailTransport */)
0125 {
0126     KCalendarCore::Attendee::List attendees = incidence->attendees();
0127     if (attendees.isEmpty()) {
0128         qCWarning(PIMKOLAB_LOG) << "There are no attendees to e-mail";
0129         return {};
0130     }
0131 
0132     const QString from = incidence->organizer().fullName();
0133     const QString organizerEmail = incidence->organizer().email();
0134 
0135     QStringList toList;
0136     QStringList ccList;
0137     const int numberOfAttendees(attendees.count());
0138     for (int i = 0; i < numberOfAttendees; ++i) {
0139         KCalendarCore::Attendee a = attendees.at(i);
0140 
0141         const QString email = a.email();
0142         if (email.isEmpty()) {
0143             continue;
0144         }
0145 
0146         // In case we (as one of our identities) are the organizer we are sending
0147         // this mail. We could also have added ourselves as an attendee, in which
0148         // case we don't want to send ourselves a notification mail.
0149         if (organizerEmail == email) {
0150             continue;
0151         }
0152 
0153         // Build a nice address for this attendee including the CN.
0154         QString tname, temail;
0155         const QString username = KEmailAddress::quoteNameIfNecessary(a.name());
0156         // ignore the return value from extractEmailAddressAndName() because
0157         // it will always be false since tusername does not contain "@domain".
0158         KEmailAddress::extractEmailAddressAndName(username, temail /*byref*/, tname /*byref*/);
0159         tname += QLatin1StringView(" <") + email + QLatin1Char('>');
0160 
0161         // Optional Participants and Non-Participants are copied on the email
0162         if (a.role() == KCalendarCore::Attendee::OptParticipant || a.role() == KCalendarCore::Attendee::NonParticipant) {
0163             ccList << tname;
0164         } else {
0165             toList << tname;
0166         }
0167     }
0168     if (toList.isEmpty() && ccList.isEmpty()) {
0169         // Not really to be called a groupware meeting, eh
0170         qCWarning(PIMKOLAB_LOG) << "There are really no attendees to e-mail";
0171         return {};
0172     }
0173     QString to;
0174     if (!toList.isEmpty()) {
0175         to = toList.join(QLatin1StringView(", "));
0176     }
0177     QString cc;
0178     if (!ccList.isEmpty()) {
0179         cc = ccList.join(QLatin1StringView(", "));
0180     }
0181 
0182     QString subject;
0183     if (incidence->type() != KCalendarCore::Incidence::TypeFreeBusy) {
0184         KCalendarCore::Incidence::Ptr inc = incidence.staticCast<KCalendarCore::Incidence>();
0185         subject = inc->summary();
0186     } else {
0187         subject = QStringLiteral("Free Busy Object");
0188     }
0189 
0190     const QString body = KCalUtils::IncidenceFormatter::mailBodyStr(incidence);
0191 
0192     return createMessage(/* identity, */ from, to, cc, subject, body, false, bccMe, attachment /*, mailTransport */)->encodedContent();
0193 }
0194 
0195 QByteArray mailOrganizer(const KCalendarCore::IncidenceBase::Ptr &incidence,
0196                          //                                 const KPIMIdentities::Identity &identity,
0197                          const QString &from,
0198                          bool bccMe,
0199                          const QString &attachment,
0200                          const QString &sub /*, const QString &mailTransport*/)
0201 {
0202     const QString to = incidence->organizer().fullName();
0203     QString subject = sub;
0204 
0205     if (incidence->type() != KCalendarCore::Incidence::TypeFreeBusy) {
0206         KCalendarCore::Incidence::Ptr inc = incidence.staticCast<KCalendarCore::Incidence>();
0207         if (subject.isEmpty()) {
0208             subject = inc->summary();
0209         }
0210     } else {
0211         subject = QStringLiteral("Free Busy Message");
0212     }
0213 
0214     QString body = KCalUtils::IncidenceFormatter::mailBodyStr(incidence);
0215 
0216     return createMessage(/*identity, */ from, to, QString(), subject, body, false, bccMe, attachment /*, mailTransport */)->encodedContent();
0217 }