From kde-commits Tue Jul 31 21:34:39 2012 From: Sergio Martins Date: Tue, 31 Jul 2012 21:34:39 +0000 To: kde-commits Subject: [kdepimlibs/calendaring] akonadi/calendar: Introduce the invitation handling code into IncidenceChan Message-Id: <20120731213439.F24A8A6094 () git ! kde ! org> X-MARC-Message: https://marc.info/?l=kde-commits&m=134377075704046 Git commit 800765f0f7553aa733d36980b18c6f4b63c3ad4f by Sergio Martins. Committed on 31/07/2012 at 23:32. Pushed by smartins into branch 'calendaring'. Introduce the invitation handling code into IncidenceChanger. M +173 -0 akonadi/calendar/incidencechanger.cpp M +3 -0 akonadi/calendar/incidencechanger.h M +9 -0 akonadi/calendar/incidencechanger_p.h M +10 -0 akonadi/calendar/invitationhandler_p.cpp M +3 -0 akonadi/calendar/invitationhandler_p.h http://commits.kde.org/kdepimlibs/800765f0f7553aa733d36980b18c6f4b63c3ad4f diff --git a/akonadi/calendar/incidencechanger.cpp b/akonadi/calendar/incid= encechanger.cpp index 87a6444..1da6ab0 100644 --- a/akonadi/calendar/incidencechanger.cpp +++ b/akonadi/calendar/incidencechanger.cpp @@ -19,6 +19,7 @@ */ #include "incidencechanger.h" #include "incidencechanger_p.h" +#include "mailscheduler_p.h" = #include #include @@ -35,6 +36,26 @@ using namespace Akonadi; using namespace KCalCore; = +InvitationHandler::Action actionFromStatus( InvitationHandler::SendResult = result ) +{ + //enum SendResult { + // Canceled, /**< Sending was canceled by the user, meaning = there are + // local changes of which other attendees are n= ot aware. */ + // FailKeepUpdate, /**< Sending failed, the changes to the inciden= ce must be kept. */ + // FailAbortUpdate, /**< Sending failed, the changes to the inciden= ce must be undone. */ + // NoSendingNeeded, /**< In some cases it is not needed to send an = invitation + // (e.g. when we are the only attendee) */ + // Success + switch ( result ) { + case InvitationHandler::ResultCanceled: + return InvitationHandler::ActionDontSendMessage; + case InvitationHandler::ResultSuccess: + return InvitationHandler::ActionSendMessage; + default: + return InvitationHandler::ActionAsk; + } +} + namespace Akonadi { static Akonadi::Collection selectCollection( QWidget *parent, int &dialogCode, @@ -142,6 +163,7 @@ IncidenceChanger::Private::Private( bool enableHistory,= IncidenceChanger *qq ) : mUseHistory =3D enableHistory; mDestinationPolicy =3D DestinationPolicyDefault; mRespectsCollectionRights =3D false; + mGroupwareCommunication =3D false; mLatestAtomicOperationId =3D 0; mBatchOperationInProgress =3D false; = @@ -415,6 +437,147 @@ bool IncidenceChanger::Private::deleteAlreadyCalled( = Akonadi::Item::Id id ) cons return mDeletedItemIds.contains( id ); } = +bool IncidenceChanger::Private::handleInvitationsBeforeChange( const Chang= e::Ptr &change ) +{ + bool result =3D true; + if ( mGroupwareCommunication ) { + InvitationHandler handler( FetchJobCalendar::Ptr(), change->parentWidg= et ); // TODO make async + if ( mInvitationStatusByAtomicOperation.contains( change->atomicOperat= ionId ) ) { + handler.setDefaultAction( actionFromStatus( mInvitationStatusByAtomi= cOperation.value( change->atomicOperationId ) ) ); + } + + switch( change->type ) { + case IncidenceChanger::ChangeTypeCreate: + // nothing needs to be done + break; + case IncidenceChanger::ChangeTypeDelete: + { + InvitationHandler::SendResult status; + + Incidence::Ptr incidence =3D change->originalItem.payload(); + status =3D handler.sendIncidenceDeletedMessage( KCalCore::iTIPCanc= el, incidence ); + if ( change->atomicOperationId ) { + mInvitationStatusByAtomicOperation.insert( change->atomicOperati= onId, status ); + } + result =3D status !=3D InvitationHandler::ResultFailAbortUpdate; + } + break; + case IncidenceChanger::ChangeTypeModify: + { + Incidence::Ptr oldIncidence =3D change->originalItem.payload(); + Incidence::Ptr newIncidence =3D change->originalItem.payload(); + + const bool modify =3D handler.handleIncidenceAboutToBeModified( ne= wIncidence ); + if ( !modify ) { + if ( newIncidence->type() =3D=3D oldIncidence->type() ) { + IncidenceBase *i1 =3D newIncidence.data(); + IncidenceBase *i2 =3D oldIncidence.data(); + *i1 =3D *i2; + } + result =3D false; + } + } + break; + default: + Q_ASSERT( false ); + result =3D false; + } + } + return result; +} + +bool IncidenceChanger::Private::handleInvitationsAfterChange( const Change= ::Ptr &change ) +{ + if ( mGroupwareCommunication ) { + InvitationHandler handler( FetchJobCalendar::Ptr(), change->parentWidg= et ); // TODO make async + switch( change->type ) { + case IncidenceChanger::ChangeTypeCreate: + { + Incidence::Ptr incidence =3D change->newItem.payload(); + const InvitationHandler::SendResult status =3D + handler.sendIncidenceCreatedMessage( KCalCore::iTIPRequest, inci= dence ); + + if ( status =3D=3D InvitationHandler::ResultFailAbortUpdate ) { + kError() << "Sending invitations failed, but did not delete the = incidence"; + } + + const uint atomicOperationId =3D change->atomicOperationId; + if ( atomicOperationId !=3D 0 ) { + mInvitationStatusByAtomicOperation.insert( atomicOperationId, st= atus ); + } + } + break; + case IncidenceChanger::ChangeTypeDelete: + { + Incidence::Ptr incidence =3D change->originalItem.payload(); + Q_ASSERT( incidence ); + if ( !handler.thatIsMe( incidence->organizer()->email() ) ) { + const QStringList myEmails =3D handler.allEmails(); + bool notifyOrganizer =3D false; + for ( QStringList::ConstIterator it =3D myEmails.begin(); it != =3D myEmails.end(); ++it ) { + const QString email =3D *it; + KCalCore::Attendee::Ptr me( incidence->attendeeByMail( email )= ); + if ( me ) { + if ( me->status() =3D=3D KCalCore::Attendee::Accepted || + me->status() =3D=3D KCalCore::Attendee::Delegated ) { + notifyOrganizer =3D true; + } + KCalCore::Attendee::Ptr newMe( new KCalCore::Attendee( *me )= ); + newMe->setStatus( KCalCore::Attendee::Declined ); + incidence->clearAttendees(); + incidence->addAttendee( newMe ); + break; + } + } + + if ( notifyOrganizer ) { + FetchJobCalendar::Ptr invalidPtr; + MailScheduler scheduler( invalidPtr ); // TODO make async + scheduler.performTransaction( incidence, KCalCore::iTIPReply ); + } + } + } + break; + case IncidenceChanger::ChangeTypeModify: + { + Incidence::Ptr oldIncidence =3D change->originalItem.payload(); + Incidence::Ptr newIncidence =3D change->newItem.payload(); + if ( mInvitationStatusByAtomicOperation.contains( change->atomicOp= erationId ) ) { + handler.setDefaultAction( actionFromStatus( mInvitationStatusByA= tomicOperation.value( change->atomicOperationId ) ) ); + } + const bool attendeeStatusChanged =3D myAttendeeStatusChanged( newI= ncidence, + oldInc= idence, + handle= r.allEmails() ); + InvitationHandler::SendResult status =3D handler.sendIncidenceModi= fiedMessage( KCalCore::iTIPRequest, + = newIncidence, + = attendeeStatusChanged ); + + if ( change->atomicOperationId !=3D 0 ) { + mInvitationStatusByAtomicOperation.insert( change->atomicOperati= onId, status ); + } + } + break; + default: + Q_ASSERT( false ); + return false; + } + } + return true; +} + +/** static */ +bool IncidenceChanger::Private::myAttendeeStatusChanged( const Incidence::= Ptr &newInc, + const Incidence::= Ptr &oldInc, + const QStringList= &myEmails ) +{ + Q_ASSERT( newInc ); + Q_ASSERT( oldInc ); + const Attendee::Ptr oldMe =3D oldInc->attendeeByMails( myEmails ); + const Attendee::Ptr newMe =3D newInc->attendeeByMails( myEmails ); + + return oldMe && newMe && oldMe->status() !=3D newMe->status(); +} + IncidenceChanger::IncidenceChanger( QObject *parent ) : QObject( parent ) , d( new Private( /*= *history=3D*/true, this ) ) { @@ -905,6 +1068,16 @@ History* IncidenceChanger::history() const return d->mHistory; } = +void IncidenceChanger::setGroupwareCommuniation( bool enabled ) +{ + d->mGroupwareCommunication =3D enabled; +} + +bool IncidenceChanger::groupwareCommunication() const +{ + return d->mGroupwareCommunication; +} + QString IncidenceChanger::Private::showErrorDialog( IncidenceChanger::Resu= ltCode resultCode, QWidget *parent ) { diff --git a/akonadi/calendar/incidencechanger.h b/akonadi/calendar/inciden= cechanger.h index 05f8722..0f3568f 100644 --- a/akonadi/calendar/incidencechanger.h +++ b/akonadi/calendar/incidencechanger.h @@ -311,6 +311,9 @@ class AKONADI_CALENDAR_EXPORT IncidenceChanger : public= QObject */ History* history() const; = + void setGroupwareCommuniation( bool enabled ); + bool groupwareCommunication() const; + Q_SIGNALS: /** * Emitted when IncidenceChanger creates an Incidence in akonadi. diff --git a/akonadi/calendar/incidencechanger_p.h b/akonadi/calendar/incid= encechanger_p.h index 9e59468..04dbdcc 100644 --- a/akonadi/calendar/incidencechanger_p.h +++ b/akonadi/calendar/incidencechanger_p.h @@ -25,6 +25,7 @@ #define AKONADI_INCIDENCECHANGER_P_H = #include "incidencechanger.h" +#include "invitationhandler_p.h" #include "history.h" = #include @@ -273,6 +274,12 @@ class IncidenceChanger::Private : public QObject void cleanupTransaction(); bool allowAtomicOperation( int atomicOperationId, const Change::Ptr &c= hange ) const; = + bool handleInvitationsBeforeChange( const Change::Ptr &change ); + bool handleInvitationsAfterChange( const Change::Ptr &change ); + static bool myAttendeeStatusChanged( const KCalCore::Incidence::Ptr &n= ewIncidence, + const KCalCore::Incidence::Ptr &o= ldIncidence, + const QStringList &myEmails ); + public Q_SLOTS: void handleCreateJobResult( KJob* ); void handleModifyJobResult( KJob* ); @@ -314,8 +321,10 @@ class IncidenceChanger::Private : public QObject QHash mAtomicOperations; = bool mRespectsCollectionRights; + bool mGroupwareCommunication; = QHash mAtomicOperationByTransacti= on; + QHash mInvitationStatusByAtomicOpe= ration; = uint mLatestAtomicOperationId; bool mBatchOperationInProgress; diff --git a/akonadi/calendar/invitationhandler_p.cpp b/akonadi/calendar/in= vitationhandler_p.cpp index b76cd6c..fd7853f 100644 --- a/akonadi/calendar/invitationhandler_p.cpp +++ b/akonadi/calendar/invitationhandler_p.cpp @@ -634,4 +634,14 @@ void InvitationHandler::onSchedulerFinished( MailSched= uler::Result result, const success ? QString() : i18n( "Error: %1", errorMsg ) ); } = +QStringList InvitationHandler::allEmails() const +{ + return d->allEmails(); +} + +bool InvitationHandler::thatIsMe( const QString &email ) const +{ + return d->thatIsMe( email ); +} + #include "invitationhandler_p.moc" diff --git a/akonadi/calendar/invitationhandler_p.h b/akonadi/calendar/invi= tationhandler_p.h index b18edf4..a6ce657 100644 --- a/akonadi/calendar/invitationhandler_p.h +++ b/akonadi/calendar/invitationhandler_p.h @@ -166,6 +166,9 @@ class InvitationHandler : public QObject // Frees calendar if it doesn't have jobs running void calendarJobFinished( bool success, const QString &errorString ); = + QStringList allEmails() const; + bool thatIsMe( const QString &email ) const; + Q_SIGNALS: /** This signal is emitted when an invitation for a counter proposal is = sent.