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>
44#include <KLocalizedString>
49static void emitiTipMessageProcessed(
ITIPHandler *handler,
51 const QString &errorString)
53 QMetaObject::invokeMethod(handler,
"iTipMessageProcessed", Qt::QueuedConnection,
55 Q_ARG(QString, errorString));
58GroupwareUiDelegate::~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;
375 d->m_showDialogsOnError = enable;
380 return d->m_calendar;
Ui delegate for editing counter proposals.
@ ResultSuccess
The invitation was sent to all attendees.
Handles sending of iTip messages aswell as processing incoming ones.
void publishInformation(const KCalCore::Incidence::Ptr &incidence, QWidget *parentWidget=0)
Publishes incidence incidence.
@ ResultCancelled
User cancelled the operation.
@ ResultSuccess
The invitation was successfuly handled.
@ ResultError
An unexpected error occurred.
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.
~ITIPHandler()
Destroys this instance.
void setGroupwareUiDelegate(GroupwareUiDelegate *)
Sets the UI delegate to edit counter proposals.
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.
void setShowDialogsOnError(bool enable)
Sets if the ITIP handler should show dialogs on error.
void processiTIPMessage(const QString &receiver, const QString &iCal, const QString &type)
Processes a received iTip message.
void setCalendar(const Akonadi::CalendarBase::Ptr &)
Sets the calendar that the itip handler should use.
void informationPublished(Akonadi::ITIPHandler::Result, const QString &errorMessage)
Signal emitted after an incidence was published with publishInformation()
FreeBusyManager::Singleton.