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-FileCopyrightText: 2012 Sérgio Martins <iamsergio@gmail.com>
9 
10   SPDX-License-Identifier: LGPL-2.0-or-later
11 */
12 
13 #pragma once
14 
15 #include "akonadi-calendar_export.h"
16 #include "etmcalendar.h"
17 
18 #include <KCalendarCore/Incidence>
19 #include <KCalendarCore/ScheduleMessage>
20 
21 #include <KGuiItem>
22 #include <KLocalizedString>
23 
24 #include <QObject>
25 #include <QString>
26 #include <QWidget>
27 
28 #include <memory>
29 
30 namespace MailTransport
31 {
32 class MessageQueueJob;
33 }
34 
35 namespace KIdentityManagement
36 {
37 class Identity;
38 }
39 
40 namespace Akonadi
41 {
42 class ITIPHandlerPrivate;
43 
44 /**
45  * @short Ui delegate for editing counter proposals.
46  * @since 4.11
47  */
48 class AKONADI_CALENDAR_EXPORT GroupwareUiDelegate : public QObject
49 {
50     Q_OBJECT
51 public:
52     explicit GroupwareUiDelegate(QObject *parent = nullptr);
53     ~GroupwareUiDelegate() override;
54 
55     virtual void requestIncidenceEditor(const Akonadi::Item &item) = 0;
56     virtual void setCalendar(const Akonadi::ETMCalendar::Ptr &calendar) = 0;
57     virtual void createCalendar() = 0;
58 };
59 
60 /**
61  * @short Ui delegate for dialogs raised by the ITIPHandler and IncidenceChanger.
62  * @since 4.15
63  */
64 class AKONADI_CALENDAR_EXPORT ITIPHandlerDialogDelegate : public QObject
65 {
66     Q_OBJECT
67 public:
68     // Possible default actions
69     enum Action {
70         ActionAsk, /**< Ask the user for a decision */
71         ActionSendMessage, /**< Answer with Yes */
72         ActionDontSendMessage /**< Answer with No */
73     };
74 
75     // How will receive the mail afterwards
76     enum Recipient {
77         Organizer, /**< the organizer of the incidence */
78         Attendees /**< the attendees of the incidence */
79     };
80 
81     /**
82      * Creates a new AskDelegator
83      */
84     explicit ITIPHandlerDialogDelegate(const KCalendarCore::Incidence::Ptr &incidence, KCalendarCore::iTIPMethod method, QWidget *parent = nullptr);
85 
86     /*
87      * Opens a Dialog, when an incidence is created
88      * The function must emit a dialogClosed signal with the user's answer
89      *
90      * @param recipient: to who the mail will be sent afterwards
91      * @param question: dialog's question
92      * @param action: Should the dialog been shown or should a default answer be returned
93      * @param buttonYes: dialog's yes answer
94      * @param buttonNo: dialog's no answer
95      */
96     virtual void openDialogIncidenceCreated(Recipient recipient,
97                                             const QString &question,
98                                             Action action = ActionAsk,
99                                             const KGuiItem &buttonYes = KGuiItem(i18nc("@action:button dialog positive answer", "Send Email")),
100                                             const KGuiItem &buttonNo = KGuiItem(i18nc("@action:button dialog negative answer", "Do Not Send")));
101 
102     /*
103      * Opens a Dialog, when an incidence is modified
104      * The function must emit a dialogClosed signal with the user's answer
105      *
106      * @param attendeeStatusChanged: Only the status of the own attendeeStatus is changed
107      * @param recipient: to who the mail will be sent afterwards
108      * @param question: dialog's question
109      * @param action: Should the dialog been shown or should a default answer be returned
110      * @param buttonYes: dialog's yes answer
111      * @param buttonNo: dialog's no answer
112      */
113     virtual void openDialogIncidenceModified(bool attendeeStatusChanged,
114                                              Recipient recipient,
115                                              const QString &question,
116                                              Action action = ActionAsk,
117                                              const KGuiItem &buttonYes = KGuiItem(i18nc("@action:button dialog positive answer", "Send Email")),
118                                              const KGuiItem &buttonNo = KGuiItem(i18nc("@action:button dialog negative answer", "Do Not Send")));
119 
120     /*
121      * Opens a Dialog, when an incidence is deleted
122      * The function must emit a dialogClosed signal with the user's answer
123      *
124      * @param recipient: to who the mail will be sent afterwards
125      * @param question: dialog's question
126      * @param action: Should the dialog been shown or should a default answer be returned
127      * @param buttonYes: dialog's yes answer
128      * @param buttonNo: dialog's no answer
129      */
130     virtual void openDialogIncidenceDeleted(Recipient recipient,
131                                             const QString &question,
132                                             Action action = ActionAsk,
133                                             const KGuiItem &buttonYes = KGuiItem(i18nc("@action:button dialog positive answer", "Send Email")),
134                                             const KGuiItem &buttonNo = KGuiItem(i18nc("@action:button dialog negative answer", "Do Not Send")));
135     /*
136      * Opens a Dialog, when mail was sended
137      * The function must emit a dialogClosed signal with the user's answer
138      *
139      * @param question: dialog's question
140      * @param action: Should the dialog been shown or should a default answer be returned
141      * @param buttonYes: dialog's yes answer
142      * @param buttonNo: dialog's no answer
143      */
144     virtual void openDialogSchedulerFinished(const QString &question,
145                                              Action action = ActionAsk,
146                                              const KGuiItem &buttonYes = KGuiItem(i18nc("@action:button dialog positive answer", "Send Email")),
147                                              const KGuiItem &buttonNo = KGuiItem(i18nc("@action:button dialog negative answer", "Do Not Send")));
148 
149 Q_SIGNALS:
150     /*
151      * Signal is emitted, when the user has answered the dialog or the defaultAction is used
152      * @param answer: answer should be part of KMessageBox:ButtonCode, keep in mind that it is a YesNoDialog so normally it should be KMessageBox::Yes or
153      * KMessageBox::No
154      * @param method: itip method
155      * @param incidence: purpose of the dialog
156      */
157     void dialogClosed(int answer, KCalendarCore::iTIPMethod method, const KCalendarCore::Incidence::Ptr &incidence);
158 
159 protected:
160     /*
161      * Opens a KMessageBox::questionYesNo with the question
162      *
163      * @return KMessageBox::Yes or KMessageBox::No
164      *
165      * @param question: dialog's question
166      * @param action: Should the dialog been shown or should a default answer be returned
167      * @param buttonYes: dialog's yes answer
168      * @param buttonNo: dialog's no answer
169      */
170     int askUserIfNeeded(const QString &question, Action action, const KGuiItem &buttonYes, const KGuiItem &buttonNo) const;
171 
172     // parent of the dialog
173     QWidget *mParent = nullptr;
174 
175     // Incidence related to the dialog
176     KCalendarCore::Incidence::Ptr mIncidence;
177 
178     // ITIPMethod related to the dialog
179     KCalendarCore::iTIPMethod mMethod;
180 };
181 
182 /**
183  * @short Factory to create MailTransport::MessageQueueJob jobs or ITIPHandlerDialogDelegate objects.
184  * @since 4.15
185  */
186 class AKONADI_CALENDAR_EXPORT ITIPHandlerComponentFactory : public QObject
187 {
188     Q_OBJECT
189 public:
190     /*
191      * Created a new ITIPHandlerComponentFactory object.
192      */
193     explicit ITIPHandlerComponentFactory(QObject *parent = nullptr);
194 
195     /*
196      * deletes the object.
197      */
198     ~ITIPHandlerComponentFactory() override;
199 
200     /*
201      * @return A new MailTransport::MessageQueueJob object
202      * @param incidence related to the mail
203      * @param identity that is the mail sender
204      * @param parent of the MailTransport::MessageQueueJob object
205      */
206     virtual MailTransport::MessageQueueJob *
207     createMessageQueueJob(const KCalendarCore::IncidenceBase::Ptr &incidence, const KIdentityManagement::Identity &identity, QObject *parent = nullptr);
208 
209     /*
210      * @return A new ITIPHandlerDialogDelegate object
211      * @param incidence the purpose of the dialogs
212      * @param method the ITIPMethod
213      * @parent parent of the AskDelegator
214      *
215      */
216     virtual ITIPHandlerDialogDelegate *
217     createITIPHanderDialogDelegate(const KCalendarCore::Incidence::Ptr &incidence, KCalendarCore::iTIPMethod method, QWidget *parent = nullptr);
218 };
219 
220 /**
221  * @short Handles sending of iTip messages as well as processing incoming ones.
222  * @since 4.11
223  */
224 class AKONADI_CALENDAR_EXPORT ITIPHandler : public QObject
225 {
226     Q_OBJECT
227 public:
228     enum Result {
229         ResultError, /**< An unexpected error occurred */
230         ResultSuccess, /**< The invitation was successfully handled. */
231         ResultCancelled /**< User cancelled the operation. @since 4.12 */
232     };
233 
234     /**
235      * Creates a new ITIPHandler instance.
236      * creates a default ITIPHandlerComponentFactory object.
237      */
238     explicit ITIPHandler(QObject *parent = nullptr);
239 
240     /**
241      * Create a new ITIPHandler instance.
242      * @param factory is set to 0 a new factory is created.
243      * @since 4.15
244      */
245     explicit ITIPHandler(ITIPHandlerComponentFactory *factory, QObject *parent);
246     /**
247      * Destroys this instance.
248      */
249     ~ITIPHandler() override;
250 
251     /**
252      * Processes a received iTip message.
253      *
254      * @param receiver
255      * @param iCal
256      * @param type
257      *
258      * @see iTipMessageProcessed()
259      */
260     void processiTIPMessage(const QString &receiver, const QString &iCal, const QString &type);
261 
262     /**
263      * Sends an iTip message.
264      *
265      * @param method iTip method
266      * @param incidence Incidence for which we're sending the iTip message.
267      *                  Should contain a list of attendees.
268      * @param parentWidget
269      */
270     void sendiTIPMessage(KCalendarCore::iTIPMethod method, const KCalendarCore::Incidence::Ptr &incidence, QWidget *parentWidget = nullptr);
271 
272     /**
273      * Publishes incidence @p incidence.
274      * A publish dialog will prompt the user to input recipients.
275      * @see rfc2446 3.2.1
276      */
277     void publishInformation(const KCalendarCore::Incidence::Ptr &incidence, QWidget *parentWidget = nullptr);
278 
279     /**
280      * Sends an e-mail with the incidence attached as iCalendar source.
281      * A dialog will prompt the user to input recipients.
282      */
283     void sendAsICalendar(const KCalendarCore::Incidence::Ptr &incidence, QWidget *parentWidget = nullptr);
284 
285     /**
286      * Sets the UI delegate to edit counter proposals.
287      */
288     void setGroupwareUiDelegate(GroupwareUiDelegate *delegate);
289 
290     /**
291      * Sets the calendar that the itip handler should use.
292      * The calendar should already be loaded.
293      *
294      * If none is set, a FetchJobCalendar will be created internally.
295      */
296     void setCalendar(const Akonadi::CalendarBase::Ptr &calendar);
297 
298     /**
299      * Sets if the ITIP handler should show dialogs on error.
300      * Default is true, for compatibility reasons, but this will change in KDE5.
301      * TODO_KDE5: use message delegates
302      *
303      * @since 4.12
304      */
305     void setShowDialogsOnError(bool enable);
306 
307     /**
308      * Returns the calendar used by this itip handler.
309      */
310     Akonadi::CalendarBase::Ptr calendar() const;
311 
312 Q_SIGNALS:
313     /**
314      * Sent after processing an incoming iTip message.
315      *
316      * @param result success of the operation.
317      * @param errorMessage translated error message suitable for user dialogs.
318      *                     Empty if the operation was successful
319      */
320     void iTipMessageProcessed(Akonadi::ITIPHandler::Result result, const QString &errorMessage);
321 
322     /**
323      * Signal emitted after an iTip message was sent through sendiTIPMessage()
324      */
325     void iTipMessageSent(Akonadi::ITIPHandler::Result, const QString &errorMessage);
326 
327     /**
328      * Signal emitted after an incidence was published with publishInformation()
329      */
330     void informationPublished(Akonadi::ITIPHandler::Result, const QString &errorMessage);
331 
332     /**
333      * Signal emitted after an incidence was sent with sendAsICalendar()
334      */
335     void sentAsICalendar(Akonadi::ITIPHandler::Result, const QString &errorMessage);
336 
337 private:
338     Q_DISABLE_COPY(ITIPHandler)
339     std::unique_ptr<ITIPHandlerPrivate> const d;
340 };
341 }
342 
343