• Skip to content
  • Skip to link menu
  • KDE API Reference
  • kdepimlibs-4.14.10 API Reference
  • KDE Home
  • Contact Us
 

akonadi

  • akonadi
  • calendar
itiphandler.cpp
1/*
2 Copyright (c) 2002-2004 Klarälvdalens Datakonsult AB
3 <info@klaralvdalens-datakonsult.se>
4
5 Copyright (C) 2010 Bertjan Broeksema <broeksema@kde.org>
6 Copyright (C) 2010 Klaralvdalens Datakonsult AB, a KDAB Group company <info@kdab.net>
7
8 Copyright (C) 2012 Sérgio Martins <iamsergio@gmail.com>
9
10 This library is free software; you can redistribute it and/or modify it
11 under the terms of the GNU Library General Public License as published by
12 the Free Software Foundation; either version 2 of the License, or (at your
13 option) any later version.
14
15 This library is distributed in the hope that it will be useful, but WITHOUT
16 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
17 FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public
18 License for more details.
19
20 You should have received a copy of the GNU Library General Public License
21 along with this library; see the file COPYING.LIB. If not, write to the
22 Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
23 02110-1301, USA.
24*/
25
26#include "itiphandler.h"
27#include "itiphandler_p.h"
28#include "itiphandlerhelper_p.h"
29#include "calendarsettings.h"
30#include "publishdialog.h"
31#include "utils_p.h"
32#include "mailclient_p.h"
33
34#include <kcalcore/icalformat.h>
35#include <kcalcore/incidence.h>
36#include <kcalcore/schedulemessage.h>
37#include <kcalcore/attendee.h>
38#include <kcalutils/stringify.h>
39
40#include <kpimidentities/identitymanager.h>
41#include <mailtransport/transportmanager.h>
42
43#include <KMessageBox>
44#include <KLocalizedString>
45
46using namespace Akonadi;
47
48// async emittion
49static void emitiTipMessageProcessed(ITIPHandler *handler,
50 ITIPHandler::Result resultCode,
51 const QString &errorString)
52{
53 QMetaObject::invokeMethod(handler, "iTipMessageProcessed", Qt::QueuedConnection,
54 Q_ARG(Akonadi::ITIPHandler::Result, resultCode),
55 Q_ARG(QString, errorString));
56}
57
58GroupwareUiDelegate::~GroupwareUiDelegate()
59{
60}
61
62ITIPHandler::ITIPHandler(QObject *parent) : QObject(parent)
63 , d(new Private(this))
64{
65 qRegisterMetaType<Akonadi::ITIPHandler::Result>("Akonadi::ITIPHandler::Result");
66}
67
68ITIPHandler::~ITIPHandler()
69{
70 delete d;
71}
72
73void ITIPHandler::processiTIPMessage(const QString &receiver,
74 const QString &iCal,
75 const QString &action)
76{
77 kDebug() << "processiTIPMessage called with receiver=" << receiver
78 << "; action=" << action;
79
80 if (d->m_currentOperation != OperationNone) {
81 d->m_currentOperation = OperationNone;
82 kFatal() << "There can't be an operation in progress!" << d->m_currentOperation;
83 return;
84 }
85
86 d->m_currentOperation = OperationProcessiTIPMessage;
87
88 if (!d->isLoaded()) {
89 d->m_queuedInvitation.receiver = receiver;
90 d->m_queuedInvitation.iCal = iCal;
91 d->m_queuedInvitation.action = action;
92 return;
93 }
94
95 if (d->m_calendarLoadError) {
96 d->m_currentOperation = OperationNone;
97 kError() << "Error loading calendar";
98 emitiTipMessageProcessed(this, ResultError, i18n("Error loading calendar."));
99 return;
100 }
101
102 KCalCore::ICalFormat format;
103 KCalCore::ScheduleMessage::Ptr message = format.parseScheduleMessage(d->calendar(), iCal);
104
105 if (!message) {
106 const QString errorMessage = format.exception() ? i18n("Error message: %1", KCalUtils::Stringify::errorMessage(*format.exception()))
107 : i18n("Unknown error while parsing iCal invitation");
108
109 kError() << "Error parsing" << errorMessage;
110
111 if (d->m_showDialogsOnError) {
112 KMessageBox::detailedError(0, // mParent, TODO
113 i18n("Error while processing an invitation or update."),
114 errorMessage);
115 }
116
117 d->m_currentOperation = OperationNone;
118 emitiTipMessageProcessed(this, ResultError, errorMessage);
119
120 return;
121 }
122
123 d->m_method = static_cast<KCalCore::iTIPMethod>(message->method());
124
125 KCalCore::ScheduleMessage::Status status = message->status();
126 d->m_incidence = message->event().dynamicCast<KCalCore::Incidence>();
127 if (!d->m_incidence) {
128 kError() << "Invalid incidence";
129 d->m_currentOperation = OperationNone;
130 emitiTipMessageProcessed(this, ResultError, i18n("Invalid incidence"));
131 return;
132 }
133
134 if (action.startsWith(QLatin1String("accepted")) ||
135 action.startsWith(QLatin1String("tentative")) ||
136 action.startsWith(QLatin1String("delegated")) ||
137 action.startsWith(QLatin1String("counter"))) {
138 // Find myself and set my status. This can't be done in the scheduler,
139 // since this does not know the choice I made in the KMail bpf
140 const KCalCore::Attendee::List attendees = d->m_incidence->attendees();
141 foreach(KCalCore::Attendee::Ptr attendee, attendees) {
142 if (attendee->email() == receiver) {
143 if (action.startsWith(QLatin1String("accepted"))) {
144 attendee->setStatus(KCalCore::Attendee::Accepted);
145 } else if (action.startsWith(QLatin1String("tentative"))) {
146 attendee->setStatus(KCalCore::Attendee::Tentative);
147 } else if (CalendarSettings::self()->outlookCompatCounterProposals() &&
148 action.startsWith(QLatin1String("counter"))) {
149 attendee->setStatus(KCalCore::Attendee::Tentative);
150 } else if (action.startsWith(QLatin1String("delegated"))) {
151 attendee->setStatus(KCalCore::Attendee::Delegated);
152 }
153 break;
154 }
155 }
156 if (CalendarSettings::self()->outlookCompatCounterProposals() ||
157 !action.startsWith(QLatin1String("counter"))) {
158 d->m_scheduler->acceptTransaction(d->m_incidence, d->calendar(), d->m_method, status, receiver);
159 return; // signal emitted in onSchedulerFinished().
160 }
161 //TODO: what happens here? we must emit a signal
162 } else if (action.startsWith(QLatin1String("cancel"))) {
163 // Delete the old incidence, if one is present
164 KCalCore::Incidence::Ptr existingIncidence = d->calendar()->incidenceFromSchedulingID(d->m_incidence->uid());
165 if (existingIncidence) {
166 d->m_scheduler->acceptTransaction(d->m_incidence, d->calendar(), KCalCore::iTIPCancel, status, receiver);
167 return; // signal emitted in onSchedulerFinished().
168 } else {
169 // We don't have the incidence, nothing to cancel
170 kWarning() << "Couldn't find the incidence to delete.\n"
171 << "You deleted it previously or didn't even accept the invitation it in the first place.\n"
172 << "; uid=" << d->m_incidence->uid()
173 << "; identifier=" << d->m_incidence->instanceIdentifier()
174 << "; summary=" << d->m_incidence->summary();
175
176 kDebug() << "\n Here's what we do have with such a summary:";
177 KCalCore::Incidence::List knownIncidences = calendar()->incidences();
178 foreach(const KCalCore::Incidence::Ptr &knownIncidence, knownIncidences) {
179 if (knownIncidence->summary() == d->m_incidence->summary()) {
180 kDebug() << "\nFound: uid=" << knownIncidence->uid()
181 << "; identifier=" << knownIncidence->instanceIdentifier()
182 << "; schedulingId" << knownIncidence->schedulingID();
183 }
184 }
185
186 emitiTipMessageProcessed(this, ResultSuccess, QString());
187 }
188 } else if (action.startsWith(QLatin1String("reply"))) {
189 if (d->m_method != KCalCore::iTIPCounter) {
190 d->m_scheduler->acceptTransaction(d->m_incidence, d->calendar(), d->m_method, status, QString());
191 } else {
192 d->m_scheduler->acceptCounterProposal(d->m_incidence, d->calendar());
193 }
194 return; // signal emitted in onSchedulerFinished().
195 } else {
196 kError() << "Unknown incoming action" << action;
197
198 d->m_currentOperation = OperationNone;
199 emitiTipMessageProcessed(this, ResultError, i18n("Invalid action: %1", action));
200 }
201
202 if (action.startsWith(QLatin1String("counter"))) {
203 if (d->m_uiDelegate) {
204 Akonadi::Item item;
205 item.setMimeType(d->m_incidence->mimeType());
206 item.setPayload(KCalCore::Incidence::Ptr(d->m_incidence->clone()));
207
208 // TODO_KDE5: This blocks because m_uiDelegate is not a QObject and can't emit a finished()
209 // signal. Make async in kde5
210 d->m_uiDelegate->requestIncidenceEditor(item);
211 KCalCore::Incidence::Ptr newIncidence;
212 if (item.hasPayload<KCalCore::Incidence::Ptr>()) {
213 newIncidence = item.payload<KCalCore::Incidence::Ptr>();
214 }
215
216 if (*newIncidence == *d->m_incidence) {
217 emitiTipMessageProcessed(this, ResultCancelled, QString());
218 } else {
219 ITIPHandlerHelper::SendResult result = d->m_helper->sendCounterProposal(d->m_incidence, newIncidence);
220 if (result != ITIPHandlerHelper::ResultSuccess) {
221 // It gives success in all paths, this never happens
222 emitiTipMessageProcessed(this, ResultError, i18n("Error sending counter proposal"));
223 Q_ASSERT(false);
224 }
225 }
226 } else {
227 // This should never happen
228 kWarning() << "No UI delegate is set";
229 emitiTipMessageProcessed(this, ResultError, i18n("Could not start editor to edit counter proposal"));
230 }
231 }
232}
233
234void ITIPHandler::sendiTIPMessage(KCalCore::iTIPMethod method,
235 const KCalCore::Incidence::Ptr &incidence,
236 QWidget *parentWidget)
237{
238 if (!incidence) {
239 Q_ASSERT(false);
240 kError() << "Invalid incidence";
241 return;
242 }
243
244 d->m_queuedInvitation.method = method;
245 d->m_queuedInvitation.incidence = incidence;
246 d->m_parentWidget = parentWidget;
247
248 if (!d->isLoaded()) {
249 // This method will be called again once the calendar is loaded.
250 return;
251 }
252
253 Q_ASSERT(d->m_currentOperation == OperationNone);
254 if (d->m_currentOperation != OperationNone) {
255 kError() << "There can't be an operation in progress!" << d->m_currentOperation;
256 return;
257 }
258
259 if (incidence->attendeeCount() == 0 && method != KCalCore::iTIPPublish) {
260 if (d->m_showDialogsOnError) {
261 KMessageBox::information(parentWidget,
262 i18n("The item '%1' has no attendees. "
263 "Therefore no groupware message will be sent.",
264 incidence->summary()),
265 i18n("Message Not Sent"),
266 QLatin1String("ScheduleNoAttendees"));
267 }
268
269 return;
270 }
271
272 d->m_currentOperation = OperationSendiTIPMessage;
273
274 KCalCore::Incidence *incidenceCopy = incidence->clone();
275 incidenceCopy->registerObserver(0);
276 incidenceCopy->clearAttendees();
277
278 d->m_scheduler->performTransaction(incidence, method);
279}
280
281void ITIPHandler::publishInformation(const KCalCore::Incidence::Ptr &incidence,
282 QWidget *parentWidget)
283{
284 Q_ASSERT(incidence);
285 if (!incidence) {
286 kError() << "Invalid incidence. Aborting.";
287 return;
288 }
289
290 Q_ASSERT(d->m_currentOperation == OperationNone);
291 if (d->m_currentOperation != OperationNone) {
292 kError() << "There can't be an operation in progress!" << d->m_currentOperation;
293 return;
294 }
295
296 d->m_queuedInvitation.incidence = incidence;
297 d->m_parentWidget = parentWidget;
298
299 d->m_currentOperation = OperationPublishInformation;
300
301 QPointer<Akonadi::PublishDialog> publishdlg = new Akonadi::PublishDialog();
302 if (incidence->attendeeCount() > 0) {
303 KCalCore::Attendee::List attendees = incidence->attendees();
304 KCalCore::Attendee::List::ConstIterator it;
305 KCalCore::Attendee::List::ConstIterator end(attendees.constEnd());
306 for (it = attendees.constBegin(); it != end; ++it) {
307 publishdlg->addAttendee(*it);
308 }
309 }
310 if (publishdlg->exec() == QDialog::Accepted && publishdlg)
311 d->m_scheduler->publish(incidence, publishdlg->addresses());
312 else
313 emit informationPublished(ResultSuccess, QString()); // Canceled.
314 delete publishdlg;
315}
316
317void ITIPHandler::sendAsICalendar(const KCalCore::Incidence::Ptr &originalIncidence,
318 QWidget *parentWidget)
319{
320 Q_UNUSED(parentWidget);
321 Q_ASSERT(originalIncidence);
322 if (!originalIncidence) {
323 kError() << "Invalid incidence";
324 return;
325 }
326
327 // Clone so we can change organizer and recurid
328 KCalCore::Incidence::Ptr incidence = KCalCore::Incidence::Ptr(originalIncidence->clone());
329
330 KPIMIdentities::IdentityManager identityManager;
331
332 QPointer<Akonadi::PublishDialog> publishdlg = new Akonadi::PublishDialog;
333 if (publishdlg->exec() == QDialog::Accepted && publishdlg) {
334 const QString recipients = publishdlg->addresses();
335 if (incidence->organizer()->isEmpty()) {
336 incidence->setOrganizer(KCalCore::Person::Ptr(
337 new KCalCore::Person(Akonadi::CalendarUtils::fullName(),
338 Akonadi::CalendarUtils::email())));
339 }
340
341 if (incidence->hasRecurrenceId()) {
342 // For an individual occurrence, recur id doesn't make sense, since we're not sending the whole recurrence series.
343 incidence->setRecurrenceId(KDateTime());
344 }
345
346 KCalCore::ICalFormat format;
347 const QString from = Akonadi::CalendarUtils::email();
348 const bool bccMe = Akonadi::CalendarSettings::self()->bcc();
349 const QString messageText = format.createScheduleMessage(incidence, KCalCore::iTIPRequest);
350 MailClient *mailer = new MailClient();
351 d->m_queuedInvitation.incidence = incidence;
352 connect(mailer, SIGNAL(finished(Akonadi::MailClient::Result,QString)),
353 d, SLOT(finishSendAsICalendar(Akonadi::MailScheduler::Result,QString)));
354
355 mailer->mailTo(incidence, identityManager.identityForAddress(from), from, bccMe,
356 recipients, messageText,
357 MailTransport::TransportManager::self()->defaultTransportName());
358 }
359}
360
361void ITIPHandler::setGroupwareUiDelegate(GroupwareUiDelegate *delegate)
362{
363 d->m_uiDelegate = delegate;
364}
365
366void ITIPHandler::setCalendar(const Akonadi::CalendarBase::Ptr &calendar)
367{
368 if (d->m_calendar != calendar) {
369 d->m_calendar = calendar;
370 }
371}
372
373void ITIPHandler::setShowDialogsOnError(bool enable)
374{
375 d->m_showDialogsOnError = enable;
376}
377
378Akonadi::CalendarBase::Ptr ITIPHandler::calendar() const
379{
380 return d->m_calendar;
381}
382
Akonadi::GroupwareUiDelegate
Ui delegate for editing counter proposals.
Definition: itiphandler.h:45
Akonadi::ITIPHandlerHelper::SendResult
SendResult
Definition: itiphandlerhelper_p.h:73
Akonadi::ITIPHandlerHelper::ResultSuccess
@ ResultSuccess
The invitation was sent to all attendees.
Definition: itiphandlerhelper_p.h:81
Akonadi::ITIPHandler
Handles sending of iTip messages aswell as processing incoming ones.
Definition: itiphandler.h:59
Akonadi::ITIPHandler::publishInformation
void publishInformation(const KCalCore::Incidence::Ptr &incidence, QWidget *parentWidget=0)
Publishes incidence incidence.
Definition: itiphandler.cpp:281
Akonadi::ITIPHandler::Result
Result
Definition: itiphandler.h:62
Akonadi::ITIPHandler::ResultCancelled
@ ResultCancelled
User cancelled the operation.
Definition: itiphandler.h:65
Akonadi::ITIPHandler::ResultSuccess
@ ResultSuccess
The invitation was successfuly handled.
Definition: itiphandler.h:64
Akonadi::ITIPHandler::ResultError
@ ResultError
An unexpected error occurred.
Definition: itiphandler.h:63
Akonadi::ITIPHandler::ITIPHandler
ITIPHandler(QObject *parent=0)
Creates a new ITIPHandler instance.
Definition: itiphandler.cpp:62
Akonadi::ITIPHandler::sendiTIPMessage
void sendiTIPMessage(KCalCore::iTIPMethod method, const KCalCore::Incidence::Ptr &incidence, QWidget *parentWidget=0)
Sends an iTip message.
Definition: itiphandler.cpp:234
Akonadi::ITIPHandler::~ITIPHandler
~ITIPHandler()
Destroys this instance.
Definition: itiphandler.cpp:68
Akonadi::ITIPHandler::setGroupwareUiDelegate
void setGroupwareUiDelegate(GroupwareUiDelegate *)
Sets the UI delegate to edit counter proposals.
Definition: itiphandler.cpp:361
Akonadi::ITIPHandler::calendar
Akonadi::CalendarBase::Ptr calendar() const
Returns the calendar used by this itip handler.
Definition: itiphandler.cpp:378
Akonadi::ITIPHandler::sendAsICalendar
void sendAsICalendar(const KCalCore::Incidence::Ptr &incidence, QWidget *parentWidget=0)
Sends an e-mail with the incidence attached as iCalendar source.
Definition: itiphandler.cpp:317
Akonadi::ITIPHandler::setShowDialogsOnError
void setShowDialogsOnError(bool enable)
Sets if the ITIP handler should show dialogs on error.
Definition: itiphandler.cpp:373
Akonadi::ITIPHandler::processiTIPMessage
void processiTIPMessage(const QString &receiver, const QString &iCal, const QString &type)
Processes a received iTip message.
Definition: itiphandler.cpp:73
Akonadi::ITIPHandler::setCalendar
void setCalendar(const Akonadi::CalendarBase::Ptr &)
Sets the calendar that the itip handler should use.
Definition: itiphandler.cpp:366
Akonadi::ITIPHandler::informationPublished
void informationPublished(Akonadi::ITIPHandler::Result, const QString &errorMessage)
Signal emitted after an incidence was published with publishInformation()
Akonadi
FreeBusyManager::Singleton.
Definition: actionstatemanager_p.h:28
This file is part of the KDE documentation.
Documentation copyright © 1996-2022 The KDE developers.
Generated on Thu Jul 21 2022 00:00:00 by doxygen 1.9.5 written by Dimitri van Heesch, © 1997-2006

KDE's Doxygen guidelines are available online.

akonadi

Skip menu "akonadi"
  • Main Page
  • Namespace List
  • Namespace Members
  • Alphabetical List
  • Class List
  • Class Hierarchy
  • Class Members
  • File List
  • Modules
  • Related Pages

kdepimlibs-4.14.10 API Reference

Skip menu "kdepimlibs-4.14.10 API Reference"
  • akonadi
  •   contact
  •   kmime
  •   socialutils
  • kabc
  • kalarmcal
  • kblog
  • kcal
  • kcalcore
  • kcalutils
  • kholidays
  • kimap
  • kioslave
  •   imap4
  •   mbox
  •   nntp
  • kldap
  • kmbox
  • kmime
  • kontactinterface
  • kpimidentities
  • kpimtextedit
  • kpimutils
  • kresources
  • ktnef
  • kxmlrpcclient
  • mailtransport
  • microblog
  • qgpgme
  • syndication
  •   atom
  •   rdf
  •   rss2
Report problems with this website to our bug tracking system.
Contact the specific authors with questions and comments about the page contents.

KDE® and the K Desktop Environment® logo are registered trademarks of KDE e.V. | Legal