26 #include "itiphandler.h"
27 #include "itiphandler_p.h"
28 #include "itiphandlerhelper_p.h"
29 #include "calendarsettings.h"
30 #include "publishdialog.h"
32 #include "mailclient_p.h"
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>
40 #include <kpimidentities/identitymanager.h>
41 #include <mailtransport/transportmanager.h>
43 #include <KMessageBox>
44 #include <KLocalizedString>
46 using namespace Akonadi;
49 static void emitiTipMessageProcessed(
ITIPHandler *handler,
51 const QString &errorString)
53 QMetaObject::invokeMethod(handler,
"iTipMessageProcessed", Qt::QueuedConnection,
55 Q_ARG(QString, errorString));
58 GroupwareUiDelegate::~GroupwareUiDelegate()
63 , d(new Private(this))
65 qRegisterMetaType<Akonadi::ITIPHandler::Result>(
"Akonadi::ITIPHandler::Result");
75 const QString &action)
77 kDebug() <<
"processiTIPMessage called with receiver=" << receiver
78 <<
"; action=" << action;
80 if (d->m_currentOperation != OperationNone) {
81 d->m_currentOperation = OperationNone;
82 kFatal() <<
"There can't be an operation in progress!" << d->m_currentOperation;
86 d->m_currentOperation = OperationProcessiTIPMessage;
89 d->m_queuedInvitation.receiver = receiver;
90 d->m_queuedInvitation.iCal = iCal;
91 d->m_queuedInvitation.action = action;
95 if (d->m_calendarLoadError) {
96 d->m_currentOperation = OperationNone;
97 kError() <<
"Error loading calendar";
98 emitiTipMessageProcessed(
this,
ResultError, i18n(
"Error loading calendar."));
102 KCalCore::ICalFormat format;
103 KCalCore::ScheduleMessage::Ptr message = format.parseScheduleMessage(d->calendar(), iCal);
106 const QString errorMessage = format.exception() ? i18n(
"Error message: %1", KCalUtils::Stringify::errorMessage(*format.exception()))
107 : i18n(
"Unknown error while parsing iCal invitation");
109 kError() <<
"Error parsing" << errorMessage;
111 if (d->m_showDialogsOnError) {
112 KMessageBox::detailedError(0,
113 i18n(
"Error while processing an invitation or update."),
117 d->m_currentOperation = OperationNone;
118 emitiTipMessageProcessed(
this,
ResultError, errorMessage);
123 d->m_method =
static_cast<KCalCore::iTIPMethod
>(message->method());
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"));
134 if (action.startsWith(QLatin1String(
"accepted")) ||
135 action.startsWith(QLatin1String(
"tentative")) ||
136 action.startsWith(QLatin1String(
"delegated")) ||
137 action.startsWith(QLatin1String(
"counter"))) {
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);
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);
162 }
else if (action.startsWith(QLatin1String(
"cancel"))) {
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);
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();
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();
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());
192 d->m_scheduler->acceptCounterProposal(d->m_incidence, d->calendar());
196 kError() <<
"Unknown incoming action" << action;
198 d->m_currentOperation = OperationNone;
199 emitiTipMessageProcessed(
this,
ResultError, i18n(
"Invalid action: %1", action));
202 if (action.startsWith(QLatin1String(
"counter"))) {
203 if (d->m_uiDelegate) {
205 item.setMimeType(d->m_incidence->mimeType());
206 item.setPayload(KCalCore::Incidence::Ptr(d->m_incidence->clone()));
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>();
216 if (*newIncidence == *d->m_incidence) {
222 emitiTipMessageProcessed(
this,
ResultError, i18n(
"Error sending counter proposal"));
228 kWarning() <<
"No UI delegate is set";
229 emitiTipMessageProcessed(
this,
ResultError, i18n(
"Could not start editor to edit counter proposal"));
235 const KCalCore::Incidence::Ptr &incidence,
236 QWidget *parentWidget)
240 kError() <<
"Invalid incidence";
244 d->m_queuedInvitation.method = method;
245 d->m_queuedInvitation.incidence = incidence;
246 d->m_parentWidget = parentWidget;
248 if (!d->isLoaded()) {
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;
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"));
272 d->m_currentOperation = OperationSendiTIPMessage;
274 KCalCore::Incidence *incidenceCopy = incidence->clone();
275 incidenceCopy->registerObserver(0);
276 incidenceCopy->clearAttendees();
278 d->m_scheduler->performTransaction(incidence, method);
282 QWidget *parentWidget)
286 kError() <<
"Invalid incidence. Aborting.";
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;
296 d->m_queuedInvitation.incidence = incidence;
297 d->m_parentWidget = parentWidget;
299 d->m_currentOperation = OperationPublishInformation;
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);
310 if (publishdlg->exec() == QDialog::Accepted && publishdlg)
311 d->m_scheduler->publish(incidence, publishdlg->addresses());
318 QWidget *parentWidget)
320 Q_UNUSED(parentWidget);
321 Q_ASSERT(originalIncidence);
322 if (!originalIncidence) {
323 kError() <<
"Invalid incidence";
328 KCalCore::Incidence::Ptr incidence = KCalCore::Incidence::Ptr(originalIncidence->clone());
330 KPIMIdentities::IdentityManager identityManager;
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())));
341 if (incidence->hasRecurrenceId()) {
343 incidence->setRecurrenceId(KDateTime());
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)));
355 mailer->mailTo(incidence, identityManager.identityForAddress(from), from, bccMe,
356 recipients, messageText,
357 MailTransport::TransportManager::self()->defaultTransportName());
363 d->m_uiDelegate = delegate;
368 if (d->m_calendar != calendar) {
375 d->m_showDialogsOnError = enable;
380 return d->m_calendar;
Akonadi::CalendarBase::Ptr calendar() const
Returns the calendar used by this itip handler.
void sendAsICalendar(const KCalCore::Incidence::Ptr &incidence, QWidget *parentWidget=0)
Sends an e-mail with the incidence attached as iCalendar source.
~ITIPHandler()
Destroys this instance.
An unexpected error occurred.
User cancelled the operation.
void informationPublished(Akonadi::ITIPHandler::Result, const QString &errorMessage)
Signal emitted after an incidence was published with publishInformation()
The invitation was successfuly handled.
void publishInformation(const KCalCore::Incidence::Ptr &incidence, QWidget *parentWidget=0)
Publishes incidence incidence.
Handles sending of iTip messages aswell as processing incoming ones.
void processiTIPMessage(const QString &receiver, const QString &iCal, const QString &type)
Processes a received iTip message.
ITIPHandler(QObject *parent=0)
Creates a new ITIPHandler instance.
void sendiTIPMessage(KCalCore::iTIPMethod method, const KCalCore::Incidence::Ptr &incidence, QWidget *parentWidget=0)
Sends an iTip message.
void setGroupwareUiDelegate(GroupwareUiDelegate *)
Sets the UI delegate to edit counter proposals.
The invitation was sent to all attendees.
void setShowDialogsOnError(bool enable)
Sets if the ITIP handler should show dialogs on error.
void setCalendar(const Akonadi::CalendarBase::Ptr &)
Sets the calendar that the itip handler should use.
Ui delegate for editing counter proposals.