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>
41 #include <kpimidentities/identitymanager.h>
42 #include <mailtransport/transportmanager.h>
44 #include <KMessageBox>
45 #include <KLocalizedString>
47 using namespace Akonadi;
50 static void emitiTipMessageProcessed(
ITIPHandler *handler,
52 const QString &errorString)
54 QMetaObject::invokeMethod(handler,
"iTipMessageProcessed", Qt::QueuedConnection,
56 Q_ARG(QString, errorString));
59 GroupwareUiDelegate::~GroupwareUiDelegate()
65 , d( new Private( this ) )
67 qRegisterMetaType<Akonadi::ITIPHandler::Result>(
"Akonadi::ITIPHandler::Result");
77 const QString &action )
79 if ( d->m_currentOperation != OperationNone ) {
80 d->m_currentOperation = OperationNone;
81 kFatal() <<
"There can't be an operation in progress!" << d->m_currentOperation;
85 d->m_currentOperation = OperationProcessiTIPMessage;
87 if ( !d->isLoaded() ) {
88 d->m_queuedInvitation.receiver = receiver;
89 d->m_queuedInvitation.iCal = iCal;
90 d->m_queuedInvitation.action = action;
94 if ( d->m_calendarLoadError ) {
95 d->m_currentOperation = OperationNone;
96 emitiTipMessageProcessed(
this,
ResultError, i18n(
"Error loading calendar." ) );
100 KCalCore::ICalFormat format;
101 KCalCore::ScheduleMessage::Ptr message = format.parseScheduleMessage( d->calendar(), iCal );
104 const QString errorMessage = format.exception() ? i18n(
"Error message: %1", KCalUtils::Stringify::errorMessage( *format.exception() ) )
105 : i18n(
"Unknown error while parsing iCal invitation" );
107 kError() <<
"Error parsing" << errorMessage;
109 KMessageBox::detailedError( 0,
110 i18n(
"Error while processing an invitation or update." ),
112 d->m_currentOperation = OperationNone;
118 d->m_method =
static_cast<KCalCore::iTIPMethod
>( message->method() );
120 KCalCore::ScheduleMessage::Status status = message->status();
121 d->m_incidence = message->event().dynamicCast<KCalCore::Incidence>();
122 if ( !d->m_incidence ) {
123 kError() <<
"Invalid incidence";
124 d->m_currentOperation = OperationNone;
125 emitiTipMessageProcessed(
this,
ResultError, i18n(
"Invalid incidence" ) );
129 if ( action.startsWith( QLatin1String(
"accepted" ) ) ||
130 action.startsWith( QLatin1String(
"tentative" ) ) ||
131 action.startsWith( QLatin1String(
"delegated" ) ) ||
132 action.startsWith( QLatin1String(
"counter" ) ) ) {
135 const KCalCore::Attendee::List attendees = d->m_incidence->attendees();
136 foreach ( KCalCore::Attendee::Ptr attendee, attendees ) {
137 if ( attendee->email() == receiver ) {
138 if ( action.startsWith( QLatin1String(
"accepted" ) ) ) {
139 attendee->setStatus( KCalCore::Attendee::Accepted );
140 }
else if ( action.startsWith( QLatin1String(
"tentative" ) ) ) {
141 attendee->setStatus( KCalCore::Attendee::Tentative );
142 }
else if ( CalendarSettings::self()->outlookCompatCounterProposals() &&
143 action.startsWith( QLatin1String(
"counter" ) ) ) {
144 attendee->setStatus( KCalCore::Attendee::Tentative );
145 }
else if ( action.startsWith( QLatin1String(
"delegated" ) ) ) {
146 attendee->setStatus( KCalCore::Attendee::Delegated );
151 if ( CalendarSettings::self()->outlookCompatCounterProposals() ||
152 !action.startsWith( QLatin1String(
"counter" ) ) ) {
153 d->m_scheduler->acceptTransaction( d->m_incidence, d->calendar(), d->m_method, status, receiver );
157 }
else if ( action.startsWith( QLatin1String(
"cancel" ) ) ) {
159 KCalCore::Incidence::Ptr existingIncidence = d->calendar()->incidenceFromSchedulingID( d->m_incidence->uid() );
160 if ( existingIncidence ) {
161 d->m_scheduler->acceptTransaction( d->m_incidence, d->calendar(), KCalCore::iTIPCancel, status, receiver );
165 kWarning() <<
"Couldn't find the incidence to delete.\n"
166 <<
"You deleted it previously or didn't even accept the invitation it in the first place.\n"
167 <<
"; uid=" << d->m_incidence->uid()
168 <<
"; identifier=" << d->m_incidence->instanceIdentifier()
169 <<
"; summary=" << d->m_incidence->summary();
171 kDebug() <<
"\n Here's what we do have with such a summary:";
172 KCalCore::Incidence::List knownIncidences =
calendar()->incidences();
173 foreach (
const KCalCore::Incidence::Ptr &knownIncidence, knownIncidences) {
174 if ( knownIncidence->summary() == d->m_incidence->summary() ) {
175 kDebug() <<
"\nFound: uid=" << knownIncidence->uid()
176 <<
"; identifier=" << knownIncidence->instanceIdentifier()
177 <<
"; schedulingId" << knownIncidence->schedulingID();
183 }
else if ( action.startsWith( QLatin1String(
"reply" ) ) ) {
184 if ( d->m_method != KCalCore::iTIPCounter ) {
185 d->m_scheduler->acceptTransaction( d->m_incidence, d->calendar(), d->m_method, status, QString() );
187 d->m_scheduler->acceptCounterProposal( d->m_incidence, d->calendar() );
191 kError() <<
"Unknown incoming action" << action;
193 d->m_currentOperation = OperationNone;
194 emitiTipMessageProcessed(
this,
ResultError, i18n(
"Invalid action: %1", action ) );
197 if ( action.startsWith( QLatin1String(
"counter" ) ) ) {
198 if ( d->m_uiDelegate ) {
200 item.setMimeType( d->m_incidence->mimeType() );
201 item.setPayload( KCalCore::Incidence::Ptr( d->m_incidence->clone() ) );
205 d->m_uiDelegate->requestIncidenceEditor( item );
206 KCalCore::Incidence::Ptr newIncidence;
207 if ( item.hasPayload<KCalCore::Incidence::Ptr>() ) {
208 newIncidence = item.payload<KCalCore::Incidence::Ptr>();
211 if ( *newIncidence == *d->m_incidence ) {
216 emitiTipMessageProcessed(
this,
ResultError, QString() );
221 emitiTipMessageProcessed(
this,
ResultError, QLatin1String(
"Error sending counter proposal") );
227 kWarning() <<
"No UI delegate is set";
228 emitiTipMessageProcessed(
this,
ResultError, QLatin1String(
"Could not start editor to edit counter proposal" ) );
234 const KCalCore::Incidence::Ptr &incidence,
235 QWidget *parentWidget )
239 kError() <<
"Invalid incidence";
243 d->m_queuedInvitation.method = method;
244 d->m_queuedInvitation.incidence = incidence;
245 d->m_parentWidget = parentWidget;
247 if ( !d->isLoaded() ) {
252 Q_ASSERT( d->m_currentOperation == OperationNone );
253 if ( d->m_currentOperation != OperationNone ) {
254 kError() <<
"There can't be an operation in progress!" << d->m_currentOperation;
258 if ( incidence->attendeeCount() == 0 && method != KCalCore::iTIPPublish ) {
259 KMessageBox::information( parentWidget,
260 i18n(
"The item '%1' has no attendees. "
261 "Therefore no groupware message will be sent.",
262 incidence->summary() ),
263 i18n(
"Message Not Sent" ),
264 QLatin1String(
"ScheduleNoAttendees" ) );
268 d->m_currentOperation = OperationSendiTIPMessage;
270 KCalCore::Incidence *incidenceCopy = incidence->clone();
271 incidenceCopy->registerObserver( 0 );
272 incidenceCopy->clearAttendees();
274 d->m_scheduler->performTransaction( incidence, method );
278 QWidget *parentWidget )
280 Q_ASSERT( incidence );
282 kError() <<
"Invalid incidence. Aborting.";
286 Q_ASSERT( d->m_currentOperation == OperationNone );
287 if ( d->m_currentOperation != OperationNone ) {
288 kError() <<
"There can't be an operation in progress!" << d->m_currentOperation;
292 d->m_queuedInvitation.incidence = incidence;
293 d->m_parentWidget = parentWidget;
295 d->m_currentOperation = OperationPublishInformation;
297 QPointer<Akonadi::PublishDialog> publishdlg =
new Akonadi::PublishDialog();
298 if ( incidence->attendeeCount() > 0 ) {
299 KCalCore::Attendee::List attendees = incidence->attendees();
300 KCalCore::Attendee::List::ConstIterator it;
301 KCalCore::Attendee::List::ConstIterator end( attendees.constEnd() );
302 for ( it = attendees.constBegin(); it != end; ++it ) {
303 publishdlg->addAttendee( *it );
306 if ( publishdlg->exec() == QDialog::Accepted && publishdlg )
307 d->m_scheduler->publish( incidence, publishdlg->addresses() );
314 QWidget *parentWidget )
316 Q_UNUSED( parentWidget );
317 Q_ASSERT( originalIncidence );
318 if ( !originalIncidence ) {
319 kError() <<
"Invalid incidence";
324 KCalCore::Incidence::Ptr incidence = KCalCore::Incidence::Ptr( originalIncidence->clone() );
326 KPIMIdentities::IdentityManager identityManager;
328 QPointer<Akonadi::PublishDialog> publishdlg =
new Akonadi::PublishDialog;
329 if ( publishdlg->exec() == QDialog::Accepted && publishdlg ) {
330 const QString recipients = publishdlg->addresses();
331 if ( incidence->organizer()->isEmpty() ) {
332 incidence->setOrganizer( KCalCore::Person::Ptr(
333 new KCalCore::Person( Akonadi::CalendarUtils::fullName(),
334 Akonadi::CalendarUtils::email() ) ) );
337 if ( incidence->hasRecurrenceId() ) {
339 incidence->setRecurrenceId(KDateTime());
342 KCalCore::ICalFormat format;
343 const QString from = Akonadi::CalendarUtils::email();
344 const bool bccMe = Akonadi::CalendarSettings::self()->bcc();
345 const QString messageText = format.createScheduleMessage( incidence, KCalCore::iTIPRequest );
346 MailClient *mailer =
new MailClient();
347 d->m_queuedInvitation.incidence = incidence;
348 connect( mailer, SIGNAL(finished(Akonadi::MailClient::Result,QString)),
349 d, SLOT(finishSendAsICalendar(Akonadi::MailScheduler::Result,QString)) );
351 mailer->mailTo( incidence, identityManager.identityForAddress( from ), from, bccMe,
352 recipients, messageText,
353 MailTransport::TransportManager::self()->defaultTransportName() );
359 d->m_uiDelegate = delegate;
364 if ( d->m_calendar != calendar ) {
371 return d->m_calendar;
374 #include "itiphandler.moc"
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.
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 iTipMessageProcessed(Akonadi::ITIPHandler::Result result, const QString &errorMessage)
Sent after processing an incoming iTip message.
void setCalendar(const Akonadi::CalendarBase::Ptr &)
Sets the calendar that the itip handler should use.
Ui delegate for editing counter proposals.