CallId Scheduler::acceptRequest( const IncidenceBase::Ptr &incidence, ScheduleMessage::Status status, const QString &email ) { Incidence::Ptr inc = incidence.staticCast<Incidence>() ; if ( !inc ) { kWarning() << "Accept what?"; return -1; } const CallId callId = ++d->mLatestCallId; ResultCode resultCode = ResultCodeSuccess; QString errorMessage; if ( inc->type() == IncidenceBase::TypeFreeBusy ) { emitOperationFinished( callId, ResultCodeSuccess, QString() ); // reply to this request is handled in korganizer's incomingdialog return callId; } const Incidence::List existingIncidences = d->mCalendar->incidencesFromSchedulingID( inc->uid() ); kDebug() << "status=" << Stringify::scheduleMessageStatus( status ) //krazy:exclude=kdebug << ": found " << existingIncidences.count() << " incidences with schedulingID " << inc->schedulingID() << "; uid was = " << inc->uid(); if ( existingIncidences.isEmpty() ) { // Perfectly normal if the incidence doesn't exist. This is probably // a new invitation. kDebug() << "incidence not found; calendar = " << d->mCalendar.data() << "; incidence count = " << d->mCalendar->incidences().count(); } Incidence::List::ConstIterator incit = existingIncidences.begin(); for ( ; incit != existingIncidences.end() ; ++incit ) { Incidence::Ptr existingIncidence = *incit; kDebug() << "Considering this found event (" << ( existingIncidence->isReadOnly() ? "readonly" : "readwrite" ) << ") :" << d->mFormat->toString( existingIncidence ); // If it's readonly, we can't possible update it. if ( existingIncidence->isReadOnly() ) { continue; } if ( existingIncidence->revision() <= inc->revision() ) { // The new incidence might be an update for the found one bool isUpdate = true; // Code for new invitations: // If you think we could check the value of "status" to be RequestNew: we can't. // It comes from a similar check inside libical, where the event is compared to // other events in the calendar. But if we have another version of the event around // (e.g. shared folder for a group), the status could be RequestNew, Obsolete or Updated. kDebug() << "looking in " << existingIncidence->uid() << "'s attendees"; // This is supposed to be a new request, not an update - however we want to update // the existing one to handle the "clicking more than once on the invitation" case. // So check the attendee status of the attendee. const Attendee::List attendees = existingIncidence->attendees(); Attendee::List::ConstIterator ait; for ( ait = attendees.begin(); ait != attendees.end(); ++ait ) { if( (*ait)->email() == email && (*ait)->status() == Attendee::NeedsAction ) { // This incidence wasn't created by me - it's probably in a shared folder // and meant for someone else, ignore it. kDebug() << "ignoring " << existingIncidence->uid() << " since I'm still NeedsAction there"; isUpdate = false; break; } } if ( isUpdate ) { if ( existingIncidence->revision() == inc->revision() && existingIncidence->lastModified() > inc->lastModified() ) { // This isn't an update - the found incidence was modified more recently deleteTransaction( existingIncidence->uid() ); errorMessage = QLatin1String( "This isn't an update - " "the found incidence was modified more recently" ); kDebug() << errorMessage; emitOperationFinished( callId, ResultCodeNotUpdate, errorMessage ); return callId; } kDebug() << "replacing existing incidence " << existingIncidence->uid(); bool emitResult = true; const QString oldUid = existingIncidence->uid(); if ( existingIncidence->type() != inc->type() ) { errorMessage = QLatin1String( "Cannot assign two different incidence types" ); resultCode = ResultCodeDifferentIncidenceTypes; } else { IncidenceBase *existingIncidenceBase = existingIncidence.data(); IncidenceBase *incBase = inc.data(); *existingIncidenceBase = *incBase; existingIncidence->setSchedulingID( inc->uid(), oldUid ); Akonadi::Item item = d->mCalendar->itemForIncidenceUid( oldUid ); item.setPayload<Incidence::Ptr>( existingIncidence ); if ( item.isValid() ) { const int changeId = d->mChanger->modifyIncidence( item ); if ( changeId >= 0 ) { d->mCallIdByChangeId.insert( changeId, callId ); emitResult = false; // will be emitted in the job result's slot. } else { resultCode = ResultCodeErrorUpdatingIncidence; errorMessage = QLatin1String( "Error while trying to update the incidence" ); } } else { resultCode = ResultCodeIncidenceNotFound; errorMessage = QLatin1String( "Couldn't find incidence in calendar" ); } } if ( emitResult ) { deleteTransaction( incidence->uid() ); emitOperationFinished( callId, resultCode, errorMessage ); } return callId; } } else { // This isn't an update - the found incidence has a bigger revision number deleteTransaction( incidence->uid() ); errorMessage = QLatin1String( "This isn't an update - " "the found incidence has a bigger revision number" ); kDebug() << errorMessage; emitOperationFinished( callId, ResultCodeNotUpdate, errorMessage ); return callId; } } // Move the uid to be the schedulingID and make a unique UID inc->setSchedulingID( inc->uid(), CalFormat::createUniqueId() ); // notify the user in case this is an update and we didn't find the to-be-updated incidence if ( existingIncidences.count() == 0 && inc->revision() > 0 ) { KMessageBox::information( 0, i18nc( "@info", "<para>You accepted an invitation update, but an earlier version of the " "item could not be found in your calendar.</para>" "<para>This may have occurred because:<list>" "<item>the organizer did not include you in the original invitation</item>" "<item>you did not accept the original invitation yet</item>" "<item>you deleted the original invitation from your calendar</item>" "<item>you no longer have access to the calendar containing the invitation</item>" "</list></para>" "<para>This is not a problem, but we thought you should know.</para>" ), i18nc( "@title", "Cannot find invitation to be updated" ), "AcceptCantFindIncidence" ); } kDebug() << "Storing new incidence with scheduling uid=" << inc->schedulingID() << " and uid=" << inc->uid(); const int changeId = d->mChanger->createIncidence( inc ); if ( changeId > 0 ) { d->mCallIdByChangeId[changeId] = callId; } else { emitOperationFinished( callId, ResultCodeErrorCreatingIncidence, QLatin1String( "Error creating incidence" ) ); } return callId; }
CallId Scheduler::acceptCancel( const IncidenceBase::Ptr &incidence, ScheduleMessage::Status status, const QString &attendee ) { Incidence::Ptr inc = incidence.staticCast<Incidence>(); if ( !inc ) { return -1; } const CallId callId = ++d->mLatestCallId; ResultCode resultCode = ResultCodeSuccess; QString errorMessage; if ( inc->type() == IncidenceBase::TypeFreeBusy ) { // reply to this request is handled in korganizer's incomingdialog emitOperationFinished( callId, resultCode, errorMessage ); return callId; } const Incidence::List existingIncidences = d->mCalendar->incidencesFromSchedulingID( inc->uid() ); kDebug() << "Scheduler::acceptCancel=" << Stringify::scheduleMessageStatus( status ) //krazy2:exclude=kdebug << ": found " << existingIncidences.count() << " incidences with schedulingID " << inc->schedulingID(); Incidence::List::ConstIterator incit = existingIncidences.begin(); for ( ; incit != existingIncidences.end() ; ++incit ) { Incidence::Ptr i = *incit; kDebug() << "Considering this found event (" << ( i->isReadOnly() ? "readonly" : "readwrite" ) << ") :" << d->mFormat->toString( i ); // If it's readonly, we can't possible remove it. if ( i->isReadOnly() ) { continue; } // Code for new invitations: // We cannot check the value of "status" to be RequestNew because // "status" comes from a similar check inside libical, where the event // is compared to other events in the calendar. But if we have another // version of the event around (e.g. shared folder for a group), the // status could be RequestNew, Obsolete or Updated. kDebug() << "looking in " << i->uid() << "'s attendees"; // This is supposed to be a new request, not an update - however we want // to update the existing one to handle the "clicking more than once // on the invitation" case. So check the attendee status of the attendee. bool isMine = true; const Attendee::List attendees = i->attendees(); Attendee::List::ConstIterator ait; for ( ait = attendees.begin(); ait != attendees.end(); ++ait ) { if ( (*ait)->email() == attendee && (*ait)->status() == Attendee::NeedsAction ) { // This incidence wasn't created by me - it's probably in a shared // folder and meant for someone else, ignore it. kDebug() << "ignoring " << i->uid() << " since I'm still NeedsAction there"; isMine = false; break; } } if ( isMine ) { //TODO_SERGIO: use ItemDeleteJob and make this async. kDebug() << "removing existing incidence " << i->uid(); Akonadi::Item item = d->mCalendar->itemForIncidenceUid( i->uid() ); bool emitResult = true; if ( item.isValid() ) { const int changeId = d->mChanger->deleteIncidence( item ); if ( changeId >= 0 ) { d->mCallIdByChangeId.insert( changeId, callId ); d->mDeletedIncidenceByChangeId.insert( changeId, i ); emitResult = false; // will be emitted in the job result's slot. } else { resultCode = ResultCodeErrorDeletingIncidence; errorMessage = QLatin1String( "Error while trying to delete the incidence" ); } } else { resultCode = ResultCodeIncidenceNotFound; errorMessage = QLatin1String( "Couldn't find incidence in calendar" ); } if ( emitResult ) { deleteTransaction( incidence->uid() ); errorMessage = QLatin1String( "Error deleting incidence" ); emitOperationFinished( callId, resultCode, errorMessage ); } return callId; } } // in case we didn't find the to-be-removed incidence if ( existingIncidences.count() > 0 && inc->revision() > 0 ) { KMessageBox::error( 0, i18nc( "@info", "The event or task could not be removed from your calendar. " "Maybe it has already been deleted or is not owned by you. " "Or it might belong to a read-only or disabled calendar." ) ); resultCode = ResultCodeIncidenceNotFound; errorMessage = QLatin1String( "Incidence not found" ); } deleteTransaction( incidence->uid() ); emitOperationFinished( callId, resultCode, errorMessage ); return callId; }
CallId Scheduler::acceptPublish( const IncidenceBase::Ptr &newIncBase, ScheduleMessage::Status status, iTIPMethod method ) { if ( newIncBase->type() == IncidenceBase::TypeFreeBusy ) { return acceptFreeBusy( newIncBase, method ); } const CallId callId = ++d->mLatestCallId; ResultCode resultCode = ResultCodeSuccess; QString errorMessage; kDebug() << "status=" << Stringify::scheduleMessageStatus( status ); //krazy:exclude=kdebug bool emitResult = true; Incidence::Ptr newInc = newIncBase.staticCast<Incidence>() ; Incidence::Ptr calInc = d->mCalendar->incidence( newIncBase->uid() ); switch ( status ) { case ScheduleMessage::Unknown: case ScheduleMessage::PublishNew: case ScheduleMessage::PublishUpdate: if ( calInc && newInc ) { if ( ( newInc->revision() > calInc->revision() ) || ( newInc->revision() == calInc->revision() && newInc->lastModified() > calInc->lastModified() ) ) { const QString oldUid = calInc->uid(); if ( calInc->type() != newInc->type() ) { kError() << "assigning different incidence types"; resultCode = ResultCodeDifferentIncidenceTypes; errorMessage = QLatin1String( "Cannot assign two different incidence types" ); } else { IncidenceBase *ci = calInc.data(); IncidenceBase *ni = newInc.data(); *ci = *ni; calInc->setSchedulingID( newInc->uid(), oldUid ); Akonadi::Item item = d->mCalendar->itemForIncidenceUid( calInc->uid() ); item.setPayload<Incidence::Ptr>( calInc ); if ( item.isValid() ) { const int changeId = d->mChanger->modifyIncidence( item ); if ( changeId >= 0 ) { d->mCallIdByChangeId.insert( changeId, callId ); emitResult = false; // will be emitted in the job result's slot. } else { resultCode = ResultCodeErrorUpdatingIncidence; errorMessage = QLatin1String( "Error while trying to update the incidence" ); } } else { resultCode = ResultCodeIncidenceNotFound; errorMessage = QLatin1String( "Couldn't find incidence in calendar" ); } } } else { resultCode = ResultCodeNewIncidenceTooOld; errorMessage = QLatin1String( "A newer existing incidence already exists" ); } } else { resultCode = ResultCodeInvalidIncidence; errorMessage = QLatin1String( "Incidence is invalid" ); } break; case ScheduleMessage::Obsolete: // Success break; default: resultCode = ResultCodeUnknownStatus; errorMessage = QLatin1String( "Unhandled ScheduleMessage status" ); break; } if ( emitResult ) { deleteTransaction( newIncBase->uid() ); // Delayed signal, the caller must know this CallId first. emitOperationFinished( callId, resultCode, errorMessage ); } return callId; }