libkcal

scheduler.cpp

00001 /*
00002     This file is part of libkcal.
00003 
00004     Copyright (c) 2001,2004 Cornelius Schumacher <schumacher@kde.org>
00005     Copyright (C) 2004 Reinhold Kainhofer <reinhold@kainhofer.com>
00006 
00007     This library is free software; you can redistribute it and/or
00008     modify it under the terms of the GNU Library General Public
00009     License as published by the Free Software Foundation; either
00010     version 2 of the License, or (at your option) any later version.
00011 
00012     This library is distributed in the hope that it will be useful,
00013     but WITHOUT ANY WARRANTY; without even the implied warranty of
00014     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00015     Library General Public License for more details.
00016 
00017     You should have received a copy of the GNU Library General Public License
00018     along with this library; see the file COPYING.LIB.  If not, write to
00019     the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
00020     Boston, MA 02110-1301, USA.
00021 */
00022 
00023 #include <klocale.h>
00024 #include <kdebug.h>
00025 #include <kmessagebox.h>
00026 #include <kstandarddirs.h>
00027 
00028 #include "event.h"
00029 #include "todo.h"
00030 #include "freebusy.h"
00031 #include "icalformat.h"
00032 #include "calendar.h"
00033 #include "calendarresources.h"
00034 #include "freebusycache.h"
00035 #include "assignmentvisitor.h"
00036 
00037 #include "scheduler.h"
00038 
00039 using namespace KCal;
00040 
00041 ScheduleMessage::ScheduleMessage(IncidenceBase *incidence,int method,ScheduleMessage::Status status)
00042 {
00043   mIncidence = incidence;
00044   mMethod = method;
00045   mStatus = status;
00046 }
00047 
00048 QString ScheduleMessage::statusName(ScheduleMessage::Status status)
00049 {
00050   switch (status) {
00051     case PublishUpdate:
00052       return i18n("Updated Publish");
00053     case PublishNew:
00054       return i18n("Publish");
00055     case Obsolete:
00056       return i18n("Obsolete");
00057     case RequestNew:
00058       return i18n("New Request");
00059     case RequestUpdate:
00060       return i18n("Updated Request");
00061     default:
00062       return i18n("Unknown Status: %1").arg(QString::number(status));
00063   }
00064 }
00065 
00066 struct Scheduler::Private
00067 {
00068   Private() : mFreeBusyCache( 0 ) {}
00069 
00070   FreeBusyCache *mFreeBusyCache;
00071 };
00072 
00073 Scheduler::Scheduler(Calendar *calendar)
00074 {
00075   mCalendar = calendar;
00076   mFormat = new ICalFormat();
00077   mFormat->setTimeZone( calendar->timeZoneId(), !calendar->isLocalTime() );
00078 
00079   d = new Private;
00080 }
00081 
00082 Scheduler::~Scheduler()
00083 {
00084   delete d;
00085 
00086   delete mFormat;
00087 }
00088 
00089 void Scheduler::setFreeBusyCache( FreeBusyCache *c )
00090 {
00091   d->mFreeBusyCache = c;
00092 }
00093 
00094 FreeBusyCache *Scheduler::freeBusyCache() const
00095 {
00096   return d->mFreeBusyCache;
00097 }
00098 
00099 bool Scheduler::acceptTransaction( IncidenceBase *incidence,
00100                                    Method method,
00101                                    ScheduleMessage::Status status,
00102                                    const QString &attendee )
00103 {
00104   kdDebug(5800) << "Scheduler::acceptTransaction, method="
00105                 << methodName( method ) << endl;
00106 
00107   switch (method) {
00108     case Publish:
00109       return acceptPublish(incidence, status, method);
00110     case Request:
00111       return acceptRequest( incidence, status, attendee );
00112     case Add:
00113       return acceptAdd(incidence, status);
00114     case Cancel:
00115       return acceptCancel(incidence, status,  attendee );
00116     case Declinecounter:
00117       return acceptDeclineCounter(incidence, status);
00118     case Reply:
00119       return acceptReply(incidence, status, method);
00120     case Refresh:
00121       return acceptRefresh(incidence, status);
00122     case Counter:
00123       return acceptCounter(incidence, status);
00124     default:
00125       break;
00126   }
00127   deleteTransaction(incidence);
00128   return false;
00129 }
00130 
00131 QString Scheduler::methodName(Method method)
00132 {
00133   switch (method) {
00134     case Publish:
00135       return QString::fromLatin1("Publish");
00136     case Request:
00137       return QString::fromLatin1("Request");
00138     case Refresh:
00139       return QString::fromLatin1("Refresh");
00140     case Cancel:
00141       return QString::fromLatin1("Cancel");
00142     case Add:
00143       return QString::fromLatin1("Add");
00144     case Reply:
00145       return QString::fromLatin1("Reply");
00146     case Counter:
00147       return QString::fromLatin1("Counter");
00148     case Declinecounter:
00149       return QString::fromLatin1("Decline Counter");
00150     default:
00151       return QString::fromLatin1("Unknown");
00152   }
00153 }
00154 
00155 QString Scheduler::translatedMethodName(Method method)
00156 {
00157   switch (method) {
00158     case Publish:
00159       return i18n("Publish");
00160     case Request:
00161       return i18n("Request");
00162     case Refresh:
00163       return i18n("Refresh");
00164     case Cancel:
00165       return i18n("Cancel");
00166     case Add:
00167       return i18n("Add");
00168     case Reply:
00169       return i18n("Reply");
00170     case Counter:
00171       return i18n("counter proposal","Counter");
00172     case Declinecounter:
00173       return i18n("decline counter proposal","Decline Counter");
00174     default:
00175       return i18n("Unknown");
00176   }
00177 }
00178 
00179 bool Scheduler::deleteTransaction(IncidenceBase *)
00180 {
00181   return true;
00182 }
00183 
00184 bool Scheduler::acceptPublish( IncidenceBase *newIncBase,
00185                                ScheduleMessage::Status status, Method method )
00186 {
00187   if( newIncBase->type() == "FreeBusy" ) {
00188     return acceptFreeBusy( newIncBase, method );
00189   }
00190 
00191   bool res = false;
00192   kdDebug(5800) << "Scheduler::acceptPublish, status="
00193                 << ScheduleMessage::statusName( status ) << endl;
00194   Incidence *newInc = static_cast<Incidence *>( newIncBase );
00195   Incidence *calInc = mCalendar->incidence( newIncBase->uid() );
00196   switch ( status ) {
00197     case ScheduleMessage::Unknown:
00198     case ScheduleMessage::PublishNew:
00199     case ScheduleMessage::PublishUpdate:
00200       if ( calInc && newInc ) {
00201         if ( (newInc->revision() > calInc->revision()) ||
00202              (newInc->revision() == calInc->revision() &&
00203                newInc->lastModified() > calInc->lastModified() ) ) {
00204           AssignmentVisitor visitor;
00205           const QString oldUid = calInc->uid();
00206           if ( !visitor.assign( calInc, newInc ) ) {
00207             kdError(5800) << "assigning different incidence types" << endl;
00208           } else {
00209             calInc->setUid( oldUid );
00210             calInc->setSchedulingID( newInc->uid() );
00211             res = true;
00212           }
00213         }
00214       }
00215       break;
00216     case ScheduleMessage::Obsolete:
00217       res = true;
00218       break;
00219     default:
00220       break;
00221   }
00222   deleteTransaction( newIncBase );
00223   return res;
00224 }
00225 
00226 bool Scheduler::acceptRequest( IncidenceBase *incidence,
00227                                ScheduleMessage::Status status,
00228                                const QString &attendee )
00229 {
00230   Incidence *inc = static_cast<Incidence *>(incidence);
00231   if ( !inc )
00232     return false;
00233   if (inc->type()=="FreeBusy") {
00234     // reply to this request is handled in korganizer's incomingdialog
00235     return true;
00236   }
00237 
00238   const Incidence::List existingIncidences = mCalendar->incidencesFromSchedulingID( inc->uid() );
00239   kdDebug(5800) << "Scheduler::acceptRequest status=" << ScheduleMessage::statusName( status ) << ": found " << existingIncidences.count() << " incidences with schedulingID " << inc->schedulingID() << endl;
00240   Incidence::List::ConstIterator incit = existingIncidences.begin();
00241   for ( ; incit != existingIncidences.end() ; ++incit ) {
00242     Incidence* const i = *incit;
00243     kdDebug(5800) << "Considering this found event ("
00244                   << ( i->isReadOnly() ? "readonly" : "readwrite" )
00245                   << ") :" << mFormat->toString( i ) << endl;
00246     // If it's readonly, we can't possible update it.
00247     if ( i->isReadOnly() )
00248       continue;
00249     if ( i->revision() <= inc->revision() ) {
00250       // The new incidence might be an update for the found one
00251       bool isUpdate = true;
00252       // Code for new invitations:
00253       // If you think we could check the value of "status" to be RequestNew: we can't.
00254       // It comes from a similar check inside libical, where the event is compared to
00255       // other events in the calendar. But if we have another version of the event around
00256       // (e.g. shared folder for a group), the status could be RequestNew, Obsolete or Updated.
00257       kdDebug(5800) << "looking in " << i->uid() << "'s attendees" << endl;
00258       // This is supposed to be a new request, not an update - however we want to update
00259       // the existing one to handle the "clicking more than once on the invitation" case.
00260       // So check the attendee status of the attendee.
00261       const KCal::Attendee::List attendees = i->attendees();
00262       KCal::Attendee::List::ConstIterator ait;
00263       for ( ait = attendees.begin(); ait != attendees.end(); ++ait ) {
00264         if( (*ait)->email() == attendee && (*ait)->status() == Attendee::NeedsAction ) {
00265           // This incidence wasn't created by me - it's probably in a shared folder
00266           // and meant for someone else, ignore it.
00267           kdDebug(5800) << "ignoring " << i->uid() << " since I'm still NeedsAction there" << endl;
00268           isUpdate = false;
00269           break;
00270         }
00271       }
00272       if ( isUpdate ) {
00273         if ( i->revision() == inc->revision() &&
00274              i->lastModified() > inc->lastModified() ) {
00275           // This isn't an update - the found incidence was modified more recently
00276           kdDebug(5800) << "This isn't an update - the found incidence was modified more recently" << endl;
00277           deleteTransaction(incidence);
00278           return false;
00279         }
00280         kdDebug(5800) << "replacing existing incidence " << i->uid() << endl;
00281         bool res = true;
00282         AssignmentVisitor visitor;
00283         const QString oldUid = i->uid();
00284         if ( !visitor.assign( i, inc ) ) {
00285           kdError(5800) << "assigning different incidence types" << endl;
00286           res = false;
00287         } else {
00288           i->setUid( oldUid );
00289           i->setSchedulingID( inc->uid() );
00290         }
00291         deleteTransaction( incidence );
00292         return res;
00293       }
00294     } else {
00295       // This isn't an update - the found incidence has a bigger revision number
00296       kdDebug(5800) << "This isn't an update - the found incidence has a bigger revision number" << endl;
00297       deleteTransaction(incidence);
00298       return false;
00299     }
00300   }
00301 
00302   // Move the uid to be the schedulingID and make a unique UID
00303   inc->setSchedulingID( inc->uid() );
00304   inc->setUid( CalFormat::createUniqueId() );
00305   // in case this is an update and we didn't find the to-be-updated incidence,
00306   // ask whether we should create a new one, or drop the update
00307   if ( existingIncidences.count() > 0 || inc->revision() == 0 ||
00308        KMessageBox::questionYesNo(
00309          0,
00310          i18n("The event, task or journal to be updated could not be found. "
00311               "Maybe it has already been deleted, or the calendar that "
00312               "contains it is disabled. Press 'Store' to create a new "
00313               "one or 'Throw away' to discard this update." ),
00314          i18n("Discard this update?"), i18n("Store"),
00315          i18n("Throw away"), "AcceptCantFindIncidence" ) == KMessageBox::Yes ) {
00316     kdDebug(5800) << "Storing new incidence with scheduling uid=" << inc->schedulingID() << " and uid=" << inc->uid() << endl;
00317 
00318     CalendarResources *stdcal = dynamic_cast<CalendarResources *>( mCalendar );
00319     if( stdcal && !stdcal->hasCalendarResources() ) {
00320       KMessageBox::sorry(
00321         0,
00322         i18n( "No calendars found, unable to save the invitation." ) );
00323       return false;
00324     }
00325 
00326     // FIXME: This is a nasty hack, since we need to set a parent for the
00327     //        resource selection dialog. However, we don't have any UI methods
00328     //        in the calendar, only in the CalendarResources::DestinationPolicy
00329     //        So we need to type-cast it and extract it from the CalendarResources
00330     QWidget *tmpparent = 0;
00331     if ( stdcal ) {
00332       tmpparent = stdcal->dialogParentWidget();
00333       stdcal->setDialogParentWidget( 0 );
00334     }
00335 
00336   TryAgain:
00337     bool success = false;
00338     if ( stdcal ) {
00339       success = stdcal->addIncidence( inc );
00340     } else {
00341       success = mCalendar->addIncidence( inc );
00342     }
00343 
00344     if ( !success ) {
00345       ErrorFormat *e = stdcal ? stdcal->exception() : 0;
00346 
00347       if ( e && e->errorCode() == KCal::ErrorFormat::UserCancel &&
00348            KMessageBox::warningYesNo(
00349              0,
00350              i18n( "You canceled the save operation. Therefore, the appointment will not be "
00351                    "stored in your calendar even though you accepted the invitation. "
00352                    "Are you certain you want to discard this invitation? " ),
00353              i18n( "Discard this invitation?" ),
00354              i18n( "Discard" ), i18n( "Go Back to Folder Selection" ) ) == KMessageBox::Yes ) {
00355         KMessageBox::information(
00356           0,
00357           i18n( "The invitation \"%1\" was not saved to your calendar "
00358                 "but you are still listed as an attendee for that appointment.\n"
00359                 "If you mistakenly accepted the invitation or do not plan to attend, please notify "
00360                 "the organizer %2 and ask them to remove you from the attendee list.").
00361           arg( inc->summary(),  inc->organizer().fullName() ) );
00362         deleteTransaction( incidence );
00363         return true;
00364       } else {
00365         goto TryAgain;
00366       }
00367 
00368       // We can have a failure if the user pressed [cancel] in the resource
00369       // selectdialog, so check the exception.
00370       if ( !e ||
00371            ( e && ( e->errorCode() != KCal::ErrorFormat::UserCancel &&
00372                     e->errorCode() != KCal::ErrorFormat::NoWritableFound ) ) ) {
00373         QString errMessage = i18n( "Unable to save %1 \"%2\"." ).
00374                              arg( i18n( inc->type() ) ).
00375                              arg( inc->summary() );
00376         KMessageBox::sorry( 0, errMessage );
00377       }
00378       return false;
00379     }
00380   }
00381   deleteTransaction( incidence );
00382   return true;
00383 }
00384 
00385 bool Scheduler::acceptAdd(IncidenceBase *incidence,ScheduleMessage::Status /* status */)
00386 {
00387   deleteTransaction(incidence);
00388   return false;
00389 }
00390 
00391 bool Scheduler::acceptCancel( IncidenceBase *incidence,
00392                               ScheduleMessage::Status status,
00393                               const QString &attendee )
00394 {
00395   Incidence *inc = static_cast<Incidence *>( incidence );
00396   if ( !inc ) {
00397     return false;
00398   }
00399 
00400   if ( inc->type() == "FreeBusy" ) {
00401     // reply to this request is handled in korganizer's incomingdialog
00402     return true;
00403   }
00404 
00405   const Incidence::List existingIncidences = mCalendar->incidencesFromSchedulingID( inc->uid() );
00406   kdDebug(5800) << "Scheduler::acceptCancel="
00407                 << ScheduleMessage::statusName( status )
00408                 << ": found " << existingIncidences.count()
00409                 << " incidences with schedulingID " << inc->schedulingID()
00410                 << endl;
00411 
00412   bool ret = false;
00413   Incidence::List::ConstIterator incit = existingIncidences.begin();
00414   for ( ; incit != existingIncidences.end() ; ++incit ) {
00415     Incidence *i = *incit;
00416     kdDebug(5800) << "Considering this found event ("
00417                   << ( i->isReadOnly() ? "readonly" : "readwrite" )
00418                   << ") :" << mFormat->toString( i ) << endl;
00419 
00420     // If it's readonly, we can't possible remove it.
00421     if ( i->isReadOnly() ) {
00422       continue;
00423     }
00424 
00425     // Code for new invitations:
00426     // We cannot check the value of "status" to be RequestNew because
00427     // "status" comes from a similar check inside libical, where the event
00428     // is compared to other events in the calendar. But if we have another
00429     // version of the event around (e.g. shared folder for a group), the
00430     // status could be RequestNew, Obsolete or Updated.
00431     kdDebug(5800) << "looking in " << i->uid() << "'s attendees" << endl;
00432 
00433     // This is supposed to be a new request, not an update - however we want
00434     // to update the existing one to handle the "clicking more than once
00435     // on the invitation" case. So check the attendee status of the attendee.
00436     bool isMine = true;
00437     const KCal::Attendee::List attendees = i->attendees();
00438     KCal::Attendee::List::ConstIterator ait;
00439     for ( ait = attendees.begin(); ait != attendees.end(); ++ait ) {
00440       if ( (*ait)->email() == attendee &&
00441            (*ait)->status() == Attendee::NeedsAction ) {
00442         // This incidence wasn't created by me - it's probably in a shared
00443         // folder and meant for someone else, ignore it.
00444         kdDebug(5800) << "ignoring " << i->uid()
00445                       << " since I'm still NeedsAction there" << endl;
00446         isMine = false;
00447         break;
00448       }
00449     }
00450 
00451     if ( isMine ) {
00452       kdDebug(5800) << "removing existing incidence " << i->uid() << endl;
00453       if ( i->type() == "Event" ) {
00454         Event *event = mCalendar->event( i->uid() );
00455         ret = ( event && mCalendar->deleteEvent( event ) );
00456       } else if ( i->type() == "Todo" ) {
00457         Todo *todo = mCalendar->todo( i->uid() );
00458         ret = ( todo && mCalendar->deleteTodo( todo ) );
00459       }
00460       deleteTransaction( incidence );
00461       return ret;
00462     }
00463   }
00464 
00465   // in case we didn't find the to-be-removed incidence
00466   if ( existingIncidences.count() > 0 && inc->revision() > 0 ) {
00467     KMessageBox::information(
00468       0,
00469       i18n( "The event or task could not be removed from your calendar. "
00470             "Maybe it has already been deleted or is not owned by you. "
00471             "Or it might belong to a read-only or disabled calendar." ) );
00472   }
00473   deleteTransaction( incidence );
00474   return ret;
00475 }
00476 
00477 bool Scheduler::acceptCancel(IncidenceBase *incidence,ScheduleMessage::Status /* status */)
00478 {
00479   const IncidenceBase *toDelete = mCalendar->incidenceFromSchedulingID( incidence->uid() );
00480 
00481   bool ret = true;
00482   if ( toDelete ) {
00483     if ( toDelete->type() == "Event" ) {
00484       Event *event = mCalendar->event( toDelete->uid() );
00485       ret = ( event && mCalendar->deleteEvent( event ) );
00486     } else if ( toDelete->type() == "Todo" ) {
00487       Todo *todo = mCalendar->todo( toDelete->uid() );
00488       ret = ( todo && mCalendar->deleteTodo( todo ) );
00489     }
00490   } else {
00491     // only complain if we failed to determine the toDelete incidence
00492     // on non-initial request.
00493     Incidence *inc = static_cast<Incidence *>( incidence );
00494     if ( inc->revision() > 0 ) {
00495       ret = false;
00496     }
00497   }
00498 
00499   if ( !ret ) {
00500     KMessageBox::information(
00501       0,
00502       i18n( "The event or task to be canceled could not be removed from your calendar. "
00503             "Maybe it has already been deleted or is not owned by you. "
00504             "Or it might belong to a read-only or disabled calendar." ) );
00505   }
00506   deleteTransaction(incidence);
00507   return ret;
00508 }
00509 
00510 bool Scheduler::acceptDeclineCounter(IncidenceBase *incidence,ScheduleMessage::Status /* status */)
00511 {
00512   deleteTransaction(incidence);
00513   return false;
00514 }
00515 
00516 //bool Scheduler::acceptFreeBusy(Incidence *incidence,ScheduleMessage::Status status)
00517 //{
00518 //  deleteTransaction(incidence);
00519 //  return false;
00520 //}
00521 
00522 bool Scheduler::acceptReply(IncidenceBase *incidence,ScheduleMessage::Status /* status */, Method method)
00523 {
00524   if(incidence->type()=="FreeBusy") {
00525     return acceptFreeBusy(incidence, method);
00526   }
00527   bool ret = false;
00528   Event *ev = mCalendar->event(incidence->uid());
00529   Todo *to = mCalendar->todo(incidence->uid());
00530 
00531   // try harder to find the correct incidence
00532   if ( !ev && !to ) {
00533     const Incidence::List list = mCalendar->incidences();
00534     for ( Incidence::List::ConstIterator it = list.begin(), end = list.end(); it != end; ++it ) {
00535       if ( (*it)->schedulingID() == incidence->uid() ) {
00536         ev = dynamic_cast<Event*>( *it );
00537         to = dynamic_cast<Todo*>( *it );
00538         break;
00539       }
00540     }
00541   }
00542 
00543   if (ev || to) {
00544     //get matching attendee in calendar
00545     kdDebug(5800) << "Scheduler::acceptTransaction match found!" << endl;
00546     Attendee::List attendeesIn = incidence->attendees();
00547     Attendee::List attendeesEv;
00548     Attendee::List attendeesNew;
00549     if (ev) attendeesEv = ev->attendees();
00550     if (to) attendeesEv = to->attendees();
00551     Attendee::List::ConstIterator inIt;
00552     Attendee::List::ConstIterator evIt;
00553     for ( inIt = attendeesIn.begin(); inIt != attendeesIn.end(); ++inIt ) {
00554       Attendee *attIn = *inIt;
00555       bool found = false;
00556       for ( evIt = attendeesEv.begin(); evIt != attendeesEv.end(); ++evIt ) {
00557         Attendee *attEv = *evIt;
00558         if (attIn->email().lower()==attEv->email().lower()) {
00559           //update attendee-info
00560           kdDebug(5800) << "Scheduler::acceptTransaction update attendee" << endl;
00561           attEv->setStatus(attIn->status());
00562           attEv->setDelegate(attIn->delegate());
00563           attEv->setDelegator(attIn->delegator());
00564           ret = true;
00565           found = true;
00566         }
00567       }
00568       if ( !found && attIn->status() != Attendee::Declined )
00569         attendeesNew.append( attIn );
00570     }
00571 
00572     bool attendeeAdded = false;
00573     for ( Attendee::List::ConstIterator it = attendeesNew.constBegin(); it != attendeesNew.constEnd(); ++it ) {
00574       Attendee* attNew = *it;
00575       QString msg = i18n("%1 wants to attend %2 but was not invited.").arg( attNew->fullName() )
00576           .arg( ev ? ev->summary() : to->summary() );
00577       if ( !attNew->delegator().isEmpty() )
00578         msg = i18n("%1 wants to attend %2 on behalf of %3.").arg( attNew->fullName() )
00579             .arg( ev ? ev->summary() : to->summary() )
00580             .arg( attNew->delegator() );
00581       if ( KMessageBox::questionYesNo( 0, msg, i18n("Uninvited attendee"),
00582            KGuiItem(i18n("Accept Attendance")), KGuiItem(i18n("Reject Attendance")) )
00583            != KMessageBox::Yes )
00584       {
00585         KCal::Incidence *cancel = dynamic_cast<Incidence*>( incidence );
00586         if ( cancel )
00587           cancel->addComment( i18n( "The organizer rejected your attendance at this meeting." ) );
00588         performTransaction( cancel ? cancel : incidence, Scheduler::Cancel, attNew->fullName() );
00589         delete cancel;
00590         continue;
00591       }
00592 
00593       Attendee *a = new Attendee( attNew->name(), attNew->email(), attNew->RSVP(),
00594                                   attNew->status(), attNew->role(), attNew->uid() );
00595       a->setDelegate( attNew->delegate() );
00596       a->setDelegator( attNew->delegator() );
00597       if ( ev )
00598         ev->addAttendee( a );
00599       else if ( to )
00600         to->addAttendee( a );
00601       ret = true;
00602       attendeeAdded = true;
00603     }
00604 
00605     // send update about new participants
00606     if ( attendeeAdded ) {
00607       bool sendMail = false;
00608       if ( ev || to ) {
00609         if ( KMessageBox::questionYesNo( 0, i18n( "An attendee was added to the incidence. "
00610                                                   "Do you want to email the attendees an update message?" ),
00611                                          i18n( "Attendee Added" ), i18n( "Send Messages" ),
00612                                          i18n( "Do Not Send" ) ) == KMessageBox::Yes ) {
00613           sendMail = true;
00614         }
00615       }
00616 
00617       if ( ev ) {
00618         ev->setRevision( ev->revision() + 1 );
00619         if ( sendMail )
00620           performTransaction( ev, Scheduler::Request );
00621       }
00622       if ( to ) {
00623         to->setRevision( to->revision() + 1 );
00624         if ( sendMail )
00625           performTransaction( to, Scheduler::Request );
00626       }
00627     }
00628 
00629     if ( ret ) {
00630       // We set at least one of the attendees, so the incidence changed
00631       // Note: This should not result in a sequence number bump
00632       if ( ev )
00633         ev->updated();
00634       else if ( to )
00635         to->updated();
00636     }
00637     if ( to ) {
00638       // for VTODO a REPLY can be used to update the completion status of
00639       // a task. see RFC2446 3.4.3
00640       Todo *update = dynamic_cast<Todo*> ( incidence );
00641       Q_ASSERT( update );
00642       if ( update && ( to->percentComplete() != update->percentComplete() ) ) {
00643         to->setPercentComplete( update->percentComplete() );
00644         to->updated();
00645       }
00646     }
00647   } else
00648     kdError(5800) << "No incidence for scheduling\n";
00649   if (ret) deleteTransaction(incidence);
00650   return ret;
00651 }
00652 
00653 bool Scheduler::acceptRefresh(IncidenceBase *incidence,ScheduleMessage::Status /* status */)
00654 {
00655   // handled in korganizer's IncomingDialog
00656   deleteTransaction(incidence);
00657   return false;
00658 }
00659 
00660 bool Scheduler::acceptCounter(IncidenceBase *incidence,ScheduleMessage::Status /* status */)
00661 {
00662   deleteTransaction(incidence);
00663   return false;
00664 }
00665 
00666 bool Scheduler::acceptFreeBusy(IncidenceBase *incidence, Method method)
00667 {
00668   if ( !d->mFreeBusyCache ) {
00669     kdError() << "KCal::Scheduler: no FreeBusyCache." << endl;
00670     return false;
00671   }
00672 
00673   FreeBusy *freebusy = static_cast<FreeBusy *>(incidence);
00674 
00675   kdDebug(5800) << "acceptFreeBusy:: freeBusyDirName: " << freeBusyDir() << endl;
00676 
00677   Person from;
00678   if(method == Scheduler::Publish) {
00679     from = freebusy->organizer();
00680   }
00681   if((method == Scheduler::Reply) && (freebusy->attendeeCount() == 1)) {
00682     Attendee *attendee = freebusy->attendees().first();
00683     from = attendee->email();
00684   }
00685 
00686   if ( !d->mFreeBusyCache->saveFreeBusy( freebusy, from ) ) return false;
00687 
00688   deleteTransaction(incidence);
00689   return true;
00690 }
KDE Home | KDE Accessibility Home | Description of Access Keys