• Skip to content
  • Skip to link menu
  • KDE API Reference
  • kdepimlibs-4.11.3 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 
41 #include <kpimidentities/identitymanager.h>
42 #include <mailtransport/transportmanager.h>
43 
44 #include <KMessageBox>
45 #include <KLocalizedString>
46 
47 using namespace Akonadi;
48 
49 // async emittion
50 static void emitiTipMessageProcessed(ITIPHandler *handler,
51  ITIPHandler::Result resultCode,
52  const QString &errorString)
53 {
54  QMetaObject::invokeMethod(handler, "iTipMessageProcessed", Qt::QueuedConnection,
55  Q_ARG(Akonadi::ITIPHandler::Result, resultCode ),
56  Q_ARG(QString, errorString));
57 }
58 
59 GroupwareUiDelegate::~GroupwareUiDelegate()
60 {
61 }
62 
63 
64 ITIPHandler::ITIPHandler( QObject *parent ) : QObject( parent )
65  , d( new Private( this ) )
66 {
67  qRegisterMetaType<Akonadi::ITIPHandler::Result>("Akonadi::ITIPHandler::Result");
68 }
69 
70 ITIPHandler::~ITIPHandler()
71 {
72  delete d;
73 }
74 
75 void ITIPHandler::processiTIPMessage( const QString &receiver,
76  const QString &iCal,
77  const QString &action )
78 {
79  if ( d->m_currentOperation != OperationNone ) {
80  d->m_currentOperation = OperationNone;
81  kFatal() << "There can't be an operation in progress!" << d->m_currentOperation;
82  return;
83  }
84 
85  d->m_currentOperation = OperationProcessiTIPMessage;
86 
87  if ( !d->isLoaded() ) {
88  d->m_queuedInvitation.receiver = receiver;
89  d->m_queuedInvitation.iCal = iCal;
90  d->m_queuedInvitation.action = action;
91  return;
92  }
93 
94  if ( d->m_calendarLoadError ) {
95  d->m_currentOperation = OperationNone;
96  emitiTipMessageProcessed( this, ResultError, i18n( "Error loading calendar." ) );
97  return;
98  }
99 
100  KCalCore::ICalFormat format;
101  KCalCore::ScheduleMessage::Ptr message = format.parseScheduleMessage( d->calendar(), iCal );
102 
103  if ( !message ) {
104  const QString errorMessage = format.exception() ? i18n( "Error message: %1", KCalUtils::Stringify::errorMessage( *format.exception() ) )
105  : i18n( "Unknown error while parsing iCal invitation" );
106 
107  kError() << "Error parsing" << errorMessage;
108 
109  KMessageBox::detailedError( 0,// mParent, TODO
110  i18n( "Error while processing an invitation or update." ),
111  errorMessage );
112  d->m_currentOperation = OperationNone;
113  emit iTipMessageProcessed( ResultError, errorMessage );
114 
115  return;
116  }
117 
118  d->m_method = static_cast<KCalCore::iTIPMethod>( message->method() );
119 
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" ) );
126  return;
127  }
128 
129  if ( action.startsWith( QLatin1String( "accepted" ) ) ||
130  action.startsWith( QLatin1String( "tentative" ) ) ||
131  action.startsWith( QLatin1String( "delegated" ) ) ||
132  action.startsWith( QLatin1String( "counter" ) ) ) {
133  // Find myself and set my status. This can't be done in the scheduler,
134  // since this does not know the choice I made in the KMail bpf
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 );
147  }
148  break;
149  }
150  }
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 );
154  return; // signal emitted in onSchedulerFinished().
155  }
156  //TODO: what happens here? we must emit a signal
157  } else if ( action.startsWith( QLatin1String( "cancel" ) ) ) {
158  // Delete the old incidence, if one is present
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 );
162  return; // signal emitted in onSchedulerFinished().
163  } else {
164  // We don't have the incidence, nothing to cancel
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();
170 
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();
178  }
179  }
180 
181  emitiTipMessageProcessed( this, ResultSuccess, QString() );
182  }
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() );
186  } else {
187  d->m_scheduler->acceptCounterProposal( d->m_incidence, d->calendar() );
188  }
189  return; // signal emitted in onSchedulerFinished().
190  } else {
191  kError() << "Unknown incoming action" << action;
192 
193  d->m_currentOperation = OperationNone;
194  emitiTipMessageProcessed( this, ResultError, i18n( "Invalid action: %1", action ) );
195  }
196 
197  if ( action.startsWith( QLatin1String( "counter" ) ) ) {
198  if ( d->m_uiDelegate ) {
199  Akonadi::Item item;
200  item.setMimeType( d->m_incidence->mimeType() );
201  item.setPayload( KCalCore::Incidence::Ptr( d->m_incidence->clone() ) );
202 
203  // TODO_KDE5: This blocks because m_uiDelegate is not a QObject and can't emit a finished()
204  // signal. Make async in kde5
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>();
209  }
210 
211  if ( *newIncidence == *d->m_incidence ) {
212  // If we emit success here, kontact will delete the invitation e-mail, but the user just
213  // cancelled the editor. As a workaround, send empty string so that kmail doesn't show
214  // the error dialog and doesn't delete the e-mail either. In master will create a ResultCanceled
215  // and remove this hack.
216  emitiTipMessageProcessed( this, ResultError, QString() );
217  } else {
218  ITIPHandlerHelper::SendResult result = d->m_helper->sendCounterProposal(d->m_incidence, newIncidence);
219  if ( result != ITIPHandlerHelper::ResultSuccess ) {
220  // It gives success in all paths, this never happens
221  emitiTipMessageProcessed( this, ResultError, QLatin1String( "Error sending counter proposal") );
222  Q_ASSERT( false );
223  }
224  }
225  } else {
226  // This should never happen
227  kWarning() << "No UI delegate is set";
228  emitiTipMessageProcessed( this, ResultError, QLatin1String( "Could not start editor to edit counter proposal" ) );
229  }
230  }
231 }
232 
233 void ITIPHandler::sendiTIPMessage( KCalCore::iTIPMethod method,
234  const KCalCore::Incidence::Ptr &incidence,
235  QWidget *parentWidget )
236 {
237  if ( !incidence ) {
238  Q_ASSERT( false );
239  kError() << "Invalid incidence";
240  return;
241  }
242 
243  d->m_queuedInvitation.method = method;
244  d->m_queuedInvitation.incidence = incidence;
245  d->m_parentWidget = parentWidget;
246 
247  if ( !d->isLoaded() ) {
248  // This method will be called again once the calendar is loaded.
249  return;
250  }
251 
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;
255  return;
256  }
257 
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" ) );
265  return;
266  }
267 
268  d->m_currentOperation = OperationSendiTIPMessage;
269 
270  KCalCore::Incidence *incidenceCopy = incidence->clone();
271  incidenceCopy->registerObserver( 0 );
272  incidenceCopy->clearAttendees();
273 
274  d->m_scheduler->performTransaction( incidence, method );
275 }
276 
277 void ITIPHandler::publishInformation( const KCalCore::Incidence::Ptr &incidence,
278  QWidget *parentWidget )
279 {
280  Q_ASSERT( incidence );
281  if ( !incidence ) {
282  kError() << "Invalid incidence. Aborting.";
283  return;
284  }
285 
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;
289  return;
290  }
291 
292  d->m_queuedInvitation.incidence = incidence;
293  d->m_parentWidget = parentWidget;
294 
295  d->m_currentOperation = OperationPublishInformation;
296 
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 );
304  }
305  }
306  if ( publishdlg->exec() == QDialog::Accepted && publishdlg )
307  d->m_scheduler->publish( incidence, publishdlg->addresses() );
308  else
309  emit informationPublished( ResultSuccess, QString() ); // Canceled.
310  delete publishdlg;
311 }
312 
313 void ITIPHandler::sendAsICalendar( const KCalCore::Incidence::Ptr &originalIncidence,
314  QWidget *parentWidget )
315 {
316  Q_UNUSED( parentWidget );
317  Q_ASSERT( originalIncidence );
318  if ( !originalIncidence ) {
319  kError() << "Invalid incidence";
320  return;
321  }
322 
323  // Clone so we can change organizer and recurid
324  KCalCore::Incidence::Ptr incidence = KCalCore::Incidence::Ptr( originalIncidence->clone() );
325 
326  KPIMIdentities::IdentityManager identityManager;
327 
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() ) ) );
335  }
336 
337  if ( incidence->hasRecurrenceId() ) {
338  // For an individual occurrence, recur id doesn't make sense, since we're not sending the whole recurrence series.
339  incidence->setRecurrenceId(KDateTime());
340  }
341 
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)) );
350 
351  mailer->mailTo( incidence, identityManager.identityForAddress( from ), from, bccMe,
352  recipients, messageText,
353  MailTransport::TransportManager::self()->defaultTransportName() );
354  }
355 }
356 
357 void ITIPHandler::setGroupwareUiDelegate( GroupwareUiDelegate *delegate )
358 {
359  d->m_uiDelegate = delegate;
360 }
361 
362 void ITIPHandler::setCalendar(const Akonadi::CalendarBase::Ptr &calendar)
363 {
364  if ( d->m_calendar != calendar ) {
365  d->m_calendar = calendar;
366  }
367 }
368 
369 Akonadi::CalendarBase::Ptr ITIPHandler::calendar() const
370 {
371  return d->m_calendar;
372 }
373 
374 #include "itiphandler.moc"
Akonadi::ITIPHandler::calendar
Akonadi::CalendarBase::Ptr calendar() const
Returns the calendar used by this itip handler.
Definition: itiphandler.cpp:369
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:313
Akonadi::ITIPHandler::~ITIPHandler
~ITIPHandler()
Destroys this instance.
Definition: itiphandler.cpp:70
Akonadi::ITIPHandler::ResultError
An unexpected error occurred.
Definition: itiphandler.h:64
Akonadi::ITIPHandler::informationPublished
void informationPublished(Akonadi::ITIPHandler::Result, const QString &errorMessage)
Signal emitted after an incidence was published with publishInformation()
Akonadi::ITIPHandler::ResultSuccess
The invitation was successfuly handled.
Definition: itiphandler.h:65
Akonadi::ITIPHandler::publishInformation
void publishInformation(const KCalCore::Incidence::Ptr &incidence, QWidget *parentWidget=0)
Publishes incidence incidence.
Definition: itiphandler.cpp:277
Akonadi::ITIPHandler
Handles sending of iTip messages aswell as processing incoming ones.
Definition: itiphandler.h:59
Akonadi::ITIPHandler::processiTIPMessage
void processiTIPMessage(const QString &receiver, const QString &iCal, const QString &type)
Processes a received iTip message.
Definition: itiphandler.cpp:75
Akonadi::ITIPHandler::ITIPHandler
ITIPHandler(QObject *parent=0)
Creates a new ITIPHandler instance.
Definition: itiphandler.cpp:64
Akonadi::ITIPHandler::sendiTIPMessage
void sendiTIPMessage(KCalCore::iTIPMethod method, const KCalCore::Incidence::Ptr &incidence, QWidget *parentWidget=0)
Sends an iTip message.
Definition: itiphandler.cpp:233
Akonadi::ITIPHandler::setGroupwareUiDelegate
void setGroupwareUiDelegate(GroupwareUiDelegate *)
Sets the UI delegate to edit counter proposals.
Definition: itiphandler.cpp:357
Akonadi::ITIPHandlerHelper::ResultSuccess
The invitation was sent to all attendees.
Definition: itiphandlerhelper_p.h:82
Akonadi::ITIPHandlerHelper::SendResult
SendResult
Definition: itiphandlerhelper_p.h:74
Akonadi::ITIPHandler::Result
Result
Definition: itiphandler.h:63
Akonadi::ITIPHandler::iTipMessageProcessed
void iTipMessageProcessed(Akonadi::ITIPHandler::Result result, const QString &errorMessage)
Sent after processing an incoming iTip message.
Akonadi::ITIPHandler::setCalendar
void setCalendar(const Akonadi::CalendarBase::Ptr &)
Sets the calendar that the itip handler should use.
Definition: itiphandler.cpp:362
Akonadi::GroupwareUiDelegate
Ui delegate for editing counter proposals.
Definition: itiphandler.h:45
This file is part of the KDE documentation.
Documentation copyright © 1996-2013 The KDE developers.
Generated on Tue Nov 26 2013 09:03:18 by doxygen 1.8.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.11.3 API Reference

Skip menu "kdepimlibs-4.11.3 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