1 /*
2   SPDX-FileCopyrightText: 2002-2004 Klarälvdalens Datakonsult AB,
3         <info@klaralvdalens-datakonsult.se>
4 
5   SPDX-FileCopyrightText: 2010 Bertjan Broeksema <broeksema@kde.org>
6   SPDX-FileCopyrightText: 2010 Klaralvdalens Datakonsult AB, a KDAB Group company <info@kdab.net>
7 
8   SPDX-License-Identifier: LGPL-2.0-or-later
9 */
10 
11 #include "itiphandlerhelper_p.h"
12 #include "calendarsettings.h"
13 #include "utils_p.h"
14 
15 #include "akonadicalendar_debug.h"
16 #include <KCalUtils/IncidenceFormatter>
17 #include <KCalUtils/Stringify>
18 #include <KCalendarCore/Calendar>
19 #include <KCalendarCore/ICalFormat>
20 #include <KLocalizedString>
21 #include <KMessageBox>
22 
23 #include <QWidget>
24 
25 using namespace Akonadi;
26 
proposalComment(const KCalendarCore::Incidence::Ptr & incidence)27 QString proposalComment(const KCalendarCore::Incidence::Ptr &incidence)
28 {
29     QString comment;
30 
31     // TODO: doesn't KCalUtils/IncidenceFormater already provide this?
32     // if not, it should go there.
33 
34     switch (incidence->type()) {
35     case KCalendarCore::IncidenceBase::TypeEvent: {
36         const QDateTime dtEnd = incidence->dateTime(KCalendarCore::Incidence::RoleDisplayEnd);
37         comment = i18n("Proposed new meeting time: %1 - %2",
38                        KCalUtils::IncidenceFormatter::dateToString(incidence->dtStart().toLocalTime().date()),
39                        KCalUtils::IncidenceFormatter::dateToString(dtEnd.toLocalTime().date()));
40         break;
41     }
42     case KCalendarCore::IncidenceBase::TypeTodo:
43         qCWarning(AKONADICALENDAR_LOG) << "NOT IMPLEMENTED: proposalComment called for to-do.";
44         break;
45     default:
46         qCWarning(AKONADICALENDAR_LOG) << "NOT IMPLEMENTED: proposalComment called for " << incidence->typeStr();
47     }
48 
49     return comment;
50 }
51 
ITIPHandlerDialogDelegate(const KCalendarCore::Incidence::Ptr & incidence,KCalendarCore::iTIPMethod method,QWidget * parent)52 ITIPHandlerDialogDelegate::ITIPHandlerDialogDelegate(const KCalendarCore::Incidence::Ptr &incidence, KCalendarCore::iTIPMethod method, QWidget *parent)
53     : mParent(parent)
54     , mIncidence(incidence)
55     , mMethod(method)
56 {
57 }
58 
askUserIfNeeded(const QString & question,Action action,const KGuiItem & buttonYes,const KGuiItem & buttonNo) const59 int ITIPHandlerDialogDelegate::askUserIfNeeded(const QString &question, Action action, const KGuiItem &buttonYes, const KGuiItem &buttonNo) const
60 {
61     Q_ASSERT_X(!question.isEmpty(), "ITIPHandlerHelper::askUser", "ask what?");
62 
63     switch (action) {
64     case ActionSendMessage:
65         return KMessageBox::Yes;
66     case ActionDontSendMessage:
67         return KMessageBox::No;
68     default:
69         return KMessageBox::questionYesNo(mParent, question, i18n("Group Scheduling Email"), buttonYes, buttonNo);
70     }
71 }
72 
openDialogIncidenceCreated(Recipient recipient,const QString & question,Action action,const KGuiItem & buttonYes,const KGuiItem & buttonNo)73 void ITIPHandlerDialogDelegate::openDialogIncidenceCreated(Recipient recipient,
74                                                            const QString &question,
75                                                            Action action,
76                                                            const KGuiItem &buttonYes,
77                                                            const KGuiItem &buttonNo)
78 {
79     Q_UNUSED(recipient)
80     const int messageBoxReturnCode = askUserIfNeeded(question, action, buttonYes, buttonNo);
81     Q_EMIT dialogClosed(messageBoxReturnCode, mMethod, mIncidence);
82 }
83 
openDialogIncidenceModified(bool attendeeStatusChanged,Recipient recipient,const QString & question,Action action,const KGuiItem & buttonYes,const KGuiItem & buttonNo)84 void ITIPHandlerDialogDelegate::openDialogIncidenceModified(bool attendeeStatusChanged,
85                                                             Recipient recipient,
86                                                             const QString &question,
87                                                             Action action,
88                                                             const KGuiItem &buttonYes,
89                                                             const KGuiItem &buttonNo)
90 {
91     Q_UNUSED(attendeeStatusChanged)
92     Q_UNUSED(recipient)
93     const int messageBoxReturnCode = askUserIfNeeded(question, action, buttonYes, buttonNo);
94     Q_EMIT dialogClosed(messageBoxReturnCode, mMethod, mIncidence);
95 }
96 
openDialogIncidenceDeleted(Recipient recipient,const QString & question,Action action,const KGuiItem & buttonYes,const KGuiItem & buttonNo)97 void ITIPHandlerDialogDelegate::openDialogIncidenceDeleted(Recipient recipient,
98                                                            const QString &question,
99                                                            Action action,
100                                                            const KGuiItem &buttonYes,
101                                                            const KGuiItem &buttonNo)
102 {
103     Q_UNUSED(recipient)
104     const int messageBoxReturnCode = askUserIfNeeded(question, action, buttonYes, buttonNo);
105     Q_EMIT dialogClosed(messageBoxReturnCode, mMethod, mIncidence);
106 }
107 
openDialogSchedulerFinished(const QString & question,Action action,const KGuiItem & buttonYes,const KGuiItem & buttonNo)108 void ITIPHandlerDialogDelegate::openDialogSchedulerFinished(const QString &question, Action action, const KGuiItem &buttonYes, const KGuiItem &buttonNo)
109 {
110     const int messageBoxReturnCode = askUserIfNeeded(question, action, buttonYes, buttonNo);
111     Q_EMIT dialogClosed(messageBoxReturnCode, mMethod, mIncidence);
112 }
113 
114 ITIPHandlerHelper::SendResult
sentInvitation(int messageBoxReturnCode,const KCalendarCore::Incidence::Ptr & incidence,KCalendarCore::iTIPMethod method)115 ITIPHandlerHelper::sentInvitation(int messageBoxReturnCode, const KCalendarCore::Incidence::Ptr &incidence, KCalendarCore::iTIPMethod method)
116 {
117     // The value represented by messageBoxReturnCode is the answer on a question
118     // which is a variant of: Do you want to send an email to the attendees?
119     //
120     // Where the email contains an invitation, modification notification or
121     // deletion notification.
122 
123     if (messageBoxReturnCode == KMessageBox::Yes) {
124         // We will be sending out a message here. Now make sure there is some summary
125         // Yes, we do modify the incidence here, but we still keep the Ptr
126         // semantics, because this change is only for sending and not stored int the
127         // local calendar.
128         KCalendarCore::Incidence::Ptr _incidence(incidence->clone());
129         if (_incidence->summary().isEmpty()) {
130             _incidence->setSummary(xi18n("<placeholder>No summary given</placeholder>"));
131         }
132 
133         // Send the mail
134         m_status = StatusSendingInvitation;
135         m_scheduler->performTransaction(_incidence, method);
136         return ITIPHandlerHelper::ResultSuccess;
137     } else if (messageBoxReturnCode == KMessageBox::No) {
138         Q_EMIT finished(ITIPHandlerHelper::ResultCanceled, QString());
139         return ITIPHandlerHelper::ResultCanceled;
140     } else {
141         Q_ASSERT(false); // TODO: Figure out if/how this can happen (by closing the dialog with x??)
142         Q_EMIT finished(ITIPHandlerHelper::ResultCanceled, QString());
143         return ITIPHandlerHelper::ResultCanceled;
144     }
145 }
146 
weAreOrganizerOf(const KCalendarCore::Incidence::Ptr & incidence)147 bool ITIPHandlerHelper::weAreOrganizerOf(const KCalendarCore::Incidence::Ptr &incidence)
148 {
149     const QString email = incidence->organizer().email();
150     return Akonadi::CalendarUtils::thatIsMe(email) || email.isEmpty() || email == QLatin1String("invalid@email.address");
151 }
152 
weNeedToSendMailFor(const KCalendarCore::Incidence::Ptr & incidence)153 bool ITIPHandlerHelper::weNeedToSendMailFor(const KCalendarCore::Incidence::Ptr &incidence)
154 {
155     if (!weAreOrganizerOf(incidence)) {
156         qCritical() << "We should be the organizer of this incidence."
157                     << "; email= " << incidence->organizer().email() << "; thatIsMe() = " << Akonadi::CalendarUtils::thatIsMe(incidence->organizer().email());
158         Q_ASSERT(false);
159         return false;
160     }
161 
162     if (incidence->attendees().isEmpty()) {
163         return false;
164     }
165 
166     // At least one attendee
167     return incidence->attendees().count() > 1 || incidence->attendees().at(0).email() != incidence->organizer().email();
168 }
169 
ITIPHandlerHelper(ITIPHandlerComponentFactory * factory,QWidget * parent)170 ITIPHandlerHelper::ITIPHandlerHelper(ITIPHandlerComponentFactory *factory, QWidget *parent)
171     : QObject(parent)
172     , mDefaultAction(ITIPHandlerDialogDelegate::ActionAsk)
173     , mParent(parent)
174     , m_factory(factory ? factory : new ITIPHandlerComponentFactory(this))
175     , m_scheduler(new MailScheduler(m_factory, this))
176     , m_status(StatusNone)
177 {
178     connect(m_scheduler, &MailScheduler::transactionFinished, this, &ITIPHandlerHelper::onSchedulerFinished);
179 }
180 
~ITIPHandlerHelper()181 ITIPHandlerHelper::~ITIPHandlerHelper()
182 {
183 }
184 
setDialogParent(QWidget * parent)185 void ITIPHandlerHelper::setDialogParent(QWidget *parent)
186 {
187     mParent = parent;
188 }
189 
setDefaultAction(ITIPHandlerDialogDelegate::Action action)190 void ITIPHandlerHelper::setDefaultAction(ITIPHandlerDialogDelegate::Action action)
191 {
192     mDefaultAction = action;
193 }
194 
sendIncidenceCreatedMessage(KCalendarCore::iTIPMethod method,const KCalendarCore::Incidence::Ptr & incidence)195 void ITIPHandlerHelper::sendIncidenceCreatedMessage(KCalendarCore::iTIPMethod method, const KCalendarCore::Incidence::Ptr &incidence)
196 {
197     /// When we created the incidence, we *must* be the organizer.
198 
199     if (!weAreOrganizerOf(incidence)) {
200         qCWarning(AKONADICALENDAR_LOG) << "Creating incidence which has another organizer! Will skip sending invitations."
201                                        << "; email= " << incidence->organizer().email()
202                                        << "; thatIsMe() = " << Akonadi::CalendarUtils::thatIsMe(incidence->organizer().email());
203         Q_EMIT sendIncidenceCreatedMessageFinished(ITIPHandlerHelper::ResultFailAbortUpdate, method, incidence);
204         Q_EMIT finished(ITIPHandlerHelper::ResultFailAbortUpdate, QString());
205         return;
206     }
207 
208     if (!weNeedToSendMailFor(incidence)) {
209         Q_EMIT sendIncidenceCreatedMessageFinished(ITIPHandlerHelper::ResultNoSendingNeeded, method, incidence);
210         Q_EMIT finished(ITIPHandlerHelper::ResultNoSendingNeeded, QString());
211         return;
212     }
213 
214     QString question;
215     if (incidence->type() == KCalendarCore::Incidence::TypeEvent) {
216         question = i18n(
217             "The event \"%1\" includes other people.\n"
218             "Do you want to email the invitation to the attendees?",
219             incidence->summary());
220     } else if (incidence->type() == KCalendarCore::Incidence::TypeTodo) {
221         question = i18n(
222             "The todo \"%1\" includes other people.\n"
223             "Do you want to email the invitation to the attendees?",
224             incidence->summary());
225     } else {
226         question = i18n(
227             "This incidence includes other people. "
228             "Should an email be sent to the attendees?");
229     }
230 
231     ITIPHandlerDialogDelegate *askDelegator = m_factory->createITIPHanderDialogDelegate(incidence, method, mParent);
232     connect(askDelegator, &ITIPHandlerDialogDelegate::dialogClosed, this, &ITIPHandlerHelper::slotIncidenceCreatedDialogClosed);
233     askDelegator->openDialogIncidenceCreated(ITIPHandlerDialogDelegate::Attendees, question, mDefaultAction);
234 }
235 
slotIncidenceCreatedDialogClosed(int messageBoxReturnCode,KCalendarCore::iTIPMethod method,const KCalendarCore::Incidence::Ptr & incidence)236 void ITIPHandlerHelper::slotIncidenceCreatedDialogClosed(int messageBoxReturnCode,
237                                                          KCalendarCore::iTIPMethod method,
238                                                          const KCalendarCore::Incidence::Ptr &incidence)
239 {
240     ITIPHandlerHelper::SendResult status = sentInvitation(messageBoxReturnCode, incidence, method);
241     Q_EMIT sendIncidenceCreatedMessageFinished(status, method, incidence);
242 }
243 
handleIncidenceAboutToBeModified(const KCalendarCore::Incidence::Ptr & incidence)244 bool ITIPHandlerHelper::handleIncidenceAboutToBeModified(const KCalendarCore::Incidence::Ptr &incidence)
245 {
246     Q_ASSERT(incidence);
247     if (!weAreOrganizerOf(incidence)) {
248         switch (incidence->type()) {
249         case KCalendarCore::Incidence::TypeEvent: {
250             const QString question = i18n(
251                 "You are not the organizer of this event. Editing it will "
252                 "bring your calendar out of sync with the organizer's calendar. "
253                 "Do you really want to edit it?");
254             const int messageBoxReturnCode = KMessageBox::warningYesNo(mParent, question);
255             return messageBoxReturnCode != KMessageBox::No;
256             break;
257         }
258         case KCalendarCore::Incidence::TypeJournal:
259         case KCalendarCore::Incidence::TypeTodo:
260             // Not sure why we handle to-dos differently regarding this
261             return true;
262             break;
263         default:
264             qCritical() << "Unknown incidence type: " << incidence->type() << incidence->typeStr();
265             Q_ASSERT_X(false, "ITIPHandlerHelper::handleIncidenceAboutToBeModified()", "Unknown incidence type");
266             return false;
267         }
268     } else {
269         return true;
270     }
271 }
272 
sendIncidenceModifiedMessage(KCalendarCore::iTIPMethod method,const KCalendarCore::Incidence::Ptr & incidence,bool attendeeStatusChanged)273 void ITIPHandlerHelper::sendIncidenceModifiedMessage(KCalendarCore::iTIPMethod method,
274                                                      const KCalendarCore::Incidence::Ptr &incidence,
275                                                      bool attendeeStatusChanged)
276 {
277     ITIPHandlerDialogDelegate *askDelegator = m_factory->createITIPHanderDialogDelegate(incidence, method, mParent);
278 
279     connect(askDelegator, &ITIPHandlerDialogDelegate::dialogClosed, this, &ITIPHandlerHelper::slotIncidenceModifiedDialogClosed);
280     // For a modified incidence, either we are the organizer or someone else.
281     if (weAreOrganizerOf(incidence)) {
282         if (weNeedToSendMailFor(incidence)) {
283             const QString question = i18n(
284                 "You changed the invitation \"%1\".\n"
285                 "Do you want to email the attendees an update message?",
286                 incidence->summary());
287 
288             askDelegator->openDialogIncidenceModified(attendeeStatusChanged,
289                                                       ITIPHandlerDialogDelegate::Attendees,
290                                                       question,
291                                                       mDefaultAction,
292                                                       KGuiItem(i18n("Send Update")));
293             return;
294         } else {
295             Q_EMIT sendIncidenceModifiedMessageFinished(ITIPHandlerHelper::ResultNoSendingNeeded, method, incidence);
296             Q_EMIT finished(ITIPHandlerHelper::ResultNoSendingNeeded, QString());
297             delete askDelegator;
298             return;
299         }
300     } else if (incidence->type() == KCalendarCore::Incidence::TypeTodo) {
301         if (method == KCalendarCore::iTIPRequest) {
302             // This is an update to be sent to the organizer
303             method = KCalendarCore::iTIPReply;
304         }
305 
306         const QString question = i18n(
307             "Do you want to send a status update to the "
308             "organizer of this task?");
309         askDelegator->openDialogIncidenceModified(attendeeStatusChanged,
310                                                   ITIPHandlerDialogDelegate::Organizer,
311                                                   question,
312                                                   mDefaultAction,
313                                                   KGuiItem(i18n("Send Update")));
314         return;
315     } else if (incidence->type() == KCalendarCore::Incidence::TypeEvent) {
316         if (attendeeStatusChanged && method == KCalendarCore::iTIPRequest) {
317             method = KCalendarCore::iTIPReply;
318             const QString question = i18n(
319                 "Your status as an attendee of this event changed. "
320                 "Do you want to send a status update to the event organizer?");
321 
322             askDelegator->openDialogIncidenceModified(attendeeStatusChanged,
323                                                       ITIPHandlerDialogDelegate::Organizer,
324                                                       question,
325                                                       mDefaultAction,
326                                                       KGuiItem(i18n("Send Update")));
327             return;
328         } else {
329             slotIncidenceModifiedDialogClosed(KMessageBox::Yes, method, incidence);
330             delete askDelegator;
331             return;
332         }
333     }
334     Q_ASSERT(false); // Shouldn't happen.
335     Q_EMIT sendIncidenceModifiedMessageFinished(ITIPHandlerHelper::ResultNoSendingNeeded, method, incidence);
336     Q_EMIT finished(ITIPHandlerHelper::ResultNoSendingNeeded, QString());
337     delete askDelegator;
338 }
339 
slotIncidenceModifiedDialogClosed(int messageBoxReturnCode,KCalendarCore::iTIPMethod method,const KCalendarCore::Incidence::Ptr & incidence)340 void ITIPHandlerHelper::slotIncidenceModifiedDialogClosed(int messageBoxReturnCode,
341                                                           KCalendarCore::iTIPMethod method,
342                                                           const KCalendarCore::Incidence::Ptr &incidence)
343 {
344     ITIPHandlerHelper::SendResult status = sentInvitation(messageBoxReturnCode, incidence, method);
345     Q_EMIT sendIncidenceModifiedMessageFinished(status, method, incidence);
346 }
347 
sendIncidenceDeletedMessage(KCalendarCore::iTIPMethod method,const KCalendarCore::Incidence::Ptr & incidence)348 void ITIPHandlerHelper::sendIncidenceDeletedMessage(KCalendarCore::iTIPMethod method, const KCalendarCore::Incidence::Ptr &incidence)
349 {
350     Q_ASSERT(incidence);
351 
352     ITIPHandlerDialogDelegate *askDelegator = m_factory->createITIPHanderDialogDelegate(incidence, method, mParent);
353 
354     connect(askDelegator, &ITIPHandlerDialogDelegate::dialogClosed, this, &ITIPHandlerHelper::slotIncidenceDeletedDialogClosed);
355 
356     // For a modified incidence, either we are the organizer or someone else.
357     if (weAreOrganizerOf(incidence)) {
358         if (weNeedToSendMailFor(incidence)) {
359             QString question;
360             if (incidence->type() == KCalendarCore::Incidence::TypeEvent) {
361                 question = i18n(
362                     "You removed the invitation \"%1\".\n"
363                     "Do you want to email the attendees that the event is canceled?",
364                     incidence->summary());
365             } else if (incidence->type() == KCalendarCore::Incidence::TypeTodo) {
366                 question = i18n(
367                     "You removed the invitation \"%1\".\n"
368                     "Do you want to email the attendees that the todo is canceled?",
369                     incidence->summary());
370             } else if (incidence->type() == KCalendarCore::Incidence::TypeJournal) {
371                 question = i18n(
372                     "You removed the invitation \"%1\".\n"
373                     "Do you want to email the attendees that the journal is canceled?",
374                     incidence->summary());
375             }
376             askDelegator->openDialogIncidenceDeleted(ITIPHandlerDialogDelegate::Attendees, question, mDefaultAction);
377             return;
378         } else {
379             Q_EMIT sendIncidenceDeletedMessageFinished(ITIPHandlerHelper::ResultNoSendingNeeded, method, incidence);
380             Q_EMIT finished(ITIPHandlerHelper::ResultNoSendingNeeded, QString());
381             delete askDelegator;
382             return;
383         }
384     } else if (incidence->type() != KCalendarCore::Incidence::TypeEvent) {
385         if (method == KCalendarCore::iTIPRequest) {
386             // This is an update to be sent to the organizer
387             method = KCalendarCore::iTIPReply;
388         }
389 
390         const QString question = (incidence->type() == KCalendarCore::Incidence::TypeTodo) ? i18n(
391                                      "Do you want to send a status update to the "
392                                      "organizer of this task?")
393                                                                                            : i18n(
394                                                                                                "Do you want to send a status update to the "
395                                                                                                "organizer of this journal?");
396         askDelegator->openDialogIncidenceDeleted(ITIPHandlerDialogDelegate::Organizer,
397                                                  question,
398                                                  mDefaultAction,
399                                                  KGuiItem(i18nc("@action:button dialog positive answer", "Send Update")));
400         return;
401     } else {
402         const QStringList myEmails = Akonadi::CalendarUtils::allEmails();
403         bool incidenceAcceptedBefore = false;
404         for (const QString &email : myEmails) {
405             const KCalendarCore::Attendee me = incidence->attendeeByMail(email);
406             if (!me.isNull() && (me.status() == KCalendarCore::Attendee::Accepted || me.status() == KCalendarCore::Attendee::Delegated)) {
407                 incidenceAcceptedBefore = true;
408                 break;
409             }
410         }
411 
412         if (incidenceAcceptedBefore) {
413             QString question = i18n(
414                 "You had previously accepted an invitation to this event. "
415                 "Do you want to send an updated response to the organizer "
416                 "declining the invitation?");
417             askDelegator->openDialogIncidenceDeleted(ITIPHandlerDialogDelegate::Organizer,
418                                                      question,
419                                                      mDefaultAction,
420                                                      KGuiItem(i18nc("@action:button dialog positive answer", "Send Update")));
421             return;
422         } else {
423             // We did not accept the event before and delete it from our calendar again,
424             // so there is no need to notify people.
425             Q_EMIT sendIncidenceDeletedMessageFinished(ITIPHandlerHelper::ResultNoSendingNeeded, method, incidence);
426             Q_EMIT finished(ITIPHandlerHelper::ResultNoSendingNeeded, QString());
427             delete askDelegator;
428             return;
429         }
430     }
431 
432     Q_ASSERT(false); // Shouldn't happen.
433     Q_EMIT sendIncidenceDeletedMessageFinished(ITIPHandlerHelper::ResultNoSendingNeeded, method, incidence);
434     Q_EMIT finished(ITIPHandlerHelper::ResultNoSendingNeeded, QString());
435     delete askDelegator;
436 }
437 
slotIncidenceDeletedDialogClosed(const int messageBoxReturnCode,KCalendarCore::iTIPMethod method,const KCalendarCore::Incidence::Ptr & incidence)438 void ITIPHandlerHelper::slotIncidenceDeletedDialogClosed(const int messageBoxReturnCode,
439                                                          KCalendarCore::iTIPMethod method,
440                                                          const KCalendarCore::Incidence::Ptr &incidence)
441 {
442     ITIPHandlerHelper::SendResult status = sentInvitation(messageBoxReturnCode, incidence, method);
443     Q_EMIT sendIncidenceDeletedMessageFinished(status, method, incidence);
444 }
445 
sendCounterProposal(const KCalendarCore::Incidence::Ptr & oldEvent,const KCalendarCore::Incidence::Ptr & newEvent)446 ITIPHandlerHelper::SendResult ITIPHandlerHelper::sendCounterProposal(const KCalendarCore::Incidence::Ptr &oldEvent,
447                                                                      const KCalendarCore::Incidence::Ptr &newEvent)
448 {
449     Q_ASSERT(oldEvent);
450     Q_ASSERT(newEvent);
451 
452     if (!oldEvent || !newEvent || *oldEvent == *newEvent) {
453         return ITIPHandlerHelper::ResultNoSendingNeeded;
454     }
455 
456     if (CalendarSettings::self()->outlookCompatCounterProposals()) {
457         KCalendarCore::Incidence::Ptr tmp(oldEvent->clone());
458         tmp->setSummary(i18n("Counter proposal: %1", newEvent->summary()));
459         tmp->setDescription(newEvent->description());
460         tmp->addComment(proposalComment(newEvent));
461 
462         return sentInvitation(KMessageBox::Yes, tmp, KCalendarCore::iTIPReply);
463     } else {
464         return sentInvitation(KMessageBox::Yes, newEvent, KCalendarCore::iTIPCounter);
465     }
466 }
467 
onSchedulerFinished(Akonadi::Scheduler::Result result,const QString & errorMsg)468 void ITIPHandlerHelper::onSchedulerFinished(Akonadi::Scheduler::Result result, const QString &errorMsg)
469 {
470     const bool success = result == MailScheduler::ResultSuccess;
471 
472     if (m_status == StatusSendingInvitation) {
473         m_status = StatusNone;
474         if (!success) {
475             const QString question(i18n("Sending group scheduling email failed."));
476 
477             ITIPHandlerDialogDelegate *askDelegator =
478                 m_factory->createITIPHanderDialogDelegate(KCalendarCore::Incidence::Ptr(), KCalendarCore::iTIPNoMethod, mParent);
479 
480             connect(askDelegator, &ITIPHandlerDialogDelegate::dialogClosed, this, &ITIPHandlerHelper::slotSchedulerFinishDialog);
481             askDelegator->openDialogSchedulerFinished(question,
482                                                       ITIPHandlerDialogDelegate::ActionAsk,
483                                                       KGuiItem(i18nc("@action:button dialog positive answer to abort question", "Abort Update")));
484             return;
485         } else {
486             // fall through
487         }
488     }
489 
490     Q_EMIT finished(success ? ResultSuccess : ResultError, success ? QString() : i18n("Error: %1", errorMsg));
491 }
492 
slotSchedulerFinishDialog(const int result,KCalendarCore::iTIPMethod method,const KCalendarCore::Incidence::Ptr & incidence)493 void ITIPHandlerHelper::slotSchedulerFinishDialog(const int result, KCalendarCore::iTIPMethod method, const KCalendarCore::Incidence::Ptr &incidence)
494 {
495     Q_UNUSED(method)
496     Q_UNUSED(incidence)
497     if (result == KMessageBox::Yes) {
498         Q_EMIT finished(ResultFailAbortUpdate, QString());
499     } else {
500         Q_EMIT finished(ResultFailKeepUpdate, QString());
501     }
502 }
503