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   // notify the user in case this is an update and we didn't find the to-be-updated incidence
00306   if ( existingIncidences.count() == 0 && inc->revision() > 0 ) {
00307     KMessageBox::information(
00308       0,
00309       i18n( "<qt>"
00310             "You accepted an invitation update, but an earlier version of the "
00311             "item could not be found in your calendar.<p>"
00312             "This may have occurred because:<ul>"
00313             "<li>the organizer did not include you in the original invitation</li>"
00314             "<li>you did not accept the original invitation yet</li>"
00315             "<li>you deleted the original invitation from your calendar</li>"
00316             "<li>you no longer have access to the calendar containing the invitation</li>"
00317             "</ul>"
00318             "This is not a problem, but we thought you should know.</qt>" ),
00319       i18n( "Cannot find invitation to be updated" ), "AcceptCantFindIncidence" );
00320   }
00321   kdDebug(5800) << "Storing new incidence with scheduling uid=" << inc->schedulingID()
00322                 << " and uid=" << inc->uid() << endl;
00323 
00324   CalendarResources *stdcal = dynamic_cast<CalendarResources *>( mCalendar );
00325   if( stdcal && !stdcal->hasCalendarResources() ) {
00326     KMessageBox::sorry(
00327       0,
00328       i18n( "No calendars found, unable to save the invitation." ) );
00329     return false;
00330   }
00331 
00332   // FIXME: This is a nasty hack, since we need to set a parent for the
00333   //        resource selection dialog. However, we don't have any UI methods
00334   //        in the calendar, only in the CalendarResources::DestinationPolicy
00335   //        So we need to type-cast it and extract it from the CalendarResources
00336   QWidget *tmpparent = 0;
00337   if ( stdcal ) {
00338     tmpparent = stdcal->dialogParentWidget();
00339     stdcal->setDialogParentWidget( 0 );
00340   }
00341 
00342 TryAgain:
00343   bool success = false;
00344   if ( stdcal ) {
00345     success = stdcal->addIncidence( inc );
00346   } else {
00347     success = mCalendar->addIncidence( inc );
00348   }
00349 
00350   if ( !success ) {
00351     ErrorFormat *e = stdcal ? stdcal->exception() : 0;
00352 
00353     if ( e && e->errorCode() == KCal::ErrorFormat::UserCancel &&
00354          KMessageBox::warningYesNo(
00355            0,
00356            i18n( "You canceled the save operation. Therefore, the appointment will not be "
00357                  "stored in your calendar even though you accepted the invitation. "
00358                  "Are you certain you want to discard this invitation? " ),
00359            i18n( "Discard this invitation?" ),
00360            i18n( "Discard" ), i18n( "Go Back to Folder Selection" ) ) == KMessageBox::Yes ) {
00361       KMessageBox::information(
00362         0,
00363         i18n( "The invitation \"%1\" was not saved to your calendar "
00364               "but you are still listed as an attendee for that appointment.\n"
00365               "If you mistakenly accepted the invitation or do not plan to attend, please notify "
00366               "the organizer %2 and ask them to remove you from the attendee list.").
00367         arg( inc->summary(),  inc->organizer().fullName() ) );
00368       deleteTransaction( incidence );
00369       return true;
00370     } else {
00371       goto TryAgain;
00372     }
00373 
00374     // We can have a failure if the user pressed [cancel] in the resource
00375     // selectdialog, so check the exception.
00376     if ( !e ||
00377          ( e && ( e->errorCode() != KCal::ErrorFormat::UserCancel &&
00378                   e->errorCode() != KCal::ErrorFormat::NoWritableFound ) ) ) {
00379       QString errMessage = i18n( "Unable to save %1 \"%2\"." ).
00380                            arg( i18n( inc->type() ) ).
00381                            arg( inc->summary() );
00382       KMessageBox::sorry( 0, errMessage );
00383     }
00384     return false;
00385   }
00386 
00387   deleteTransaction( incidence );
00388   return true;
00389 }
00390 
00391 bool Scheduler::acceptAdd(IncidenceBase *incidence,ScheduleMessage::Status /* status */)
00392 {
00393   deleteTransaction(incidence);
00394   return false;
00395 }
00396 
00397 bool Scheduler::acceptCancel( IncidenceBase *incidence,
00398                               ScheduleMessage::Status status,
00399                               const QString &attendee )
00400 {
00401   Incidence *inc = static_cast<Incidence *>( incidence );
00402   if ( !inc ) {
00403     return false;
00404   }
00405 
00406   if ( inc->type() == "FreeBusy" ) {
00407     // reply to this request is handled in korganizer's incomingdialog
00408     return true;
00409   }
00410 
00411   const Incidence::List existingIncidences = mCalendar->incidencesFromSchedulingID( inc->uid() );
00412   kdDebug(5800) << "Scheduler::acceptCancel="
00413                 << ScheduleMessage::statusName( status )
00414                 << ": found " << existingIncidences.count()
00415                 << " incidences with schedulingID " << inc->schedulingID()
00416                 << endl;
00417 
00418   bool ret = false;
00419   Incidence::List::ConstIterator incit = existingIncidences.begin();
00420   for ( ; incit != existingIncidences.end() ; ++incit ) {
00421     Incidence *i = *incit;
00422     kdDebug(5800) << "Considering this found event ("
00423                   << ( i->isReadOnly() ? "readonly" : "readwrite" )
00424                   << ") :" << mFormat->toString( i ) << endl;
00425 
00426     // If it's readonly, we can't possible remove it.
00427     if ( i->isReadOnly() ) {
00428       continue;
00429     }
00430 
00431     // Code for new invitations:
00432     // We cannot check the value of "status" to be RequestNew because
00433     // "status" comes from a similar check inside libical, where the event
00434     // is compared to other events in the calendar. But if we have another
00435     // version of the event around (e.g. shared folder for a group), the
00436     // status could be RequestNew, Obsolete or Updated.
00437     kdDebug(5800) << "looking in " << i->uid() << "'s attendees" << endl;
00438 
00439     // This is supposed to be a new request, not an update - however we want
00440     // to update the existing one to handle the "clicking more than once
00441     // on the invitation" case. So check the attendee status of the attendee.
00442     bool isMine = true;
00443     const KCal::Attendee::List attendees = i->attendees();
00444     KCal::Attendee::List::ConstIterator ait;
00445     for ( ait = attendees.begin(); ait != attendees.end(); ++ait ) {
00446       if ( (*ait)->email() == attendee &&
00447            (*ait)->status() == Attendee::NeedsAction ) {
00448         // This incidence wasn't created by me - it's probably in a shared
00449         // folder and meant for someone else, ignore it.
00450         kdDebug(5800) << "ignoring " << i->uid()
00451                       << " since I'm still NeedsAction there" << endl;
00452         isMine = false;
00453         break;
00454       }
00455     }
00456 
00457     if ( isMine ) {
00458       kdDebug(5800) << "removing existing incidence " << i->uid() << endl;
00459       if ( i->type() == "Event" ) {
00460         Event *event = mCalendar->event( i->uid() );
00461         ret = ( event && mCalendar->deleteEvent( event ) );
00462       } else if ( i->type() == "Todo" ) {
00463         Todo *todo = mCalendar->todo( i->uid() );
00464         ret = ( todo && mCalendar->deleteTodo( todo ) );
00465       }
00466       deleteTransaction( incidence );
00467       return ret;
00468     }
00469   }
00470 
00471   // in case we didn't find the to-be-removed incidence
00472   if ( existingIncidences.count() > 0 && inc->revision() > 0 ) {
00473     KMessageBox::information(
00474       0,
00475       i18n( "The event or task could not be removed from your calendar. "
00476             "Maybe it has already been deleted or is not owned by you. "
00477             "Or it might belong to a read-only or disabled calendar." ) );
00478   }
00479   deleteTransaction( incidence );
00480   return ret;
00481 }
00482 
00483 bool Scheduler::acceptCancel(IncidenceBase *incidence,ScheduleMessage::Status /* status */)
00484 {
00485   const IncidenceBase *toDelete = mCalendar->incidenceFromSchedulingID( incidence->uid() );
00486 
00487   bool ret = true;
00488   if ( toDelete ) {
00489     if ( toDelete->type() == "Event" ) {
00490       Event *event = mCalendar->event( toDelete->uid() );
00491       ret = ( event && mCalendar->deleteEvent( event ) );
00492     } else if ( toDelete->type() == "Todo" ) {
00493       Todo *todo = mCalendar->todo( toDelete->uid() );
00494       ret = ( todo && mCalendar->deleteTodo( todo ) );
00495     }
00496   } else {
00497     // only complain if we failed to determine the toDelete incidence
00498     // on non-initial request.
00499     Incidence *inc = static_cast<Incidence *>( incidence );
00500     if ( inc->revision() > 0 ) {
00501       ret = false;
00502     }
00503   }
00504 
00505   if ( !ret ) {
00506     KMessageBox::information(
00507       0,
00508       i18n( "The event or task to be canceled could not be removed from your calendar. "
00509             "Maybe it has already been deleted or is not owned by you. "
00510             "Or it might belong to a read-only or disabled calendar." ) );
00511   }
00512   deleteTransaction(incidence);
00513   return ret;
00514 }
00515 
00516 bool Scheduler::acceptDeclineCounter(IncidenceBase *incidence,ScheduleMessage::Status /* status */)
00517 {
00518   deleteTransaction(incidence);
00519   return false;
00520 }
00521 
00522 //bool Scheduler::acceptFreeBusy(Incidence *incidence,ScheduleMessage::Status status)
00523 //{
00524 //  deleteTransaction(incidence);
00525 //  return false;
00526 //}
00527 
00528 bool Scheduler::acceptReply(IncidenceBase *incidence,ScheduleMessage::Status /* status */, Method method)
00529 {
00530   if(incidence->type()=="FreeBusy") {
00531     return acceptFreeBusy(incidence, method);
00532   }
00533   bool ret = false;
00534   Event *ev = mCalendar->event(incidence->uid());
00535   Todo *to = mCalendar->todo(incidence->uid());
00536 
00537   // try harder to find the correct incidence
00538   if ( !ev && !to ) {
00539     const Incidence::List list = mCalendar->incidences();
00540     for ( Incidence::List::ConstIterator it = list.begin(), end = list.end(); it != end; ++it ) {
00541       if ( (*it)->schedulingID() == incidence->uid() ) {
00542         ev = dynamic_cast<Event*>( *it );
00543         to = dynamic_cast<Todo*>( *it );
00544         break;
00545       }
00546     }
00547   }
00548 
00549   if (ev || to) {
00550     //get matching attendee in calendar
00551     kdDebug(5800) << "Scheduler::acceptTransaction match found!" << endl;
00552     Attendee::List attendeesIn = incidence->attendees();
00553     Attendee::List attendeesEv;
00554     Attendee::List attendeesNew;
00555     if (ev) attendeesEv = ev->attendees();
00556     if (to) attendeesEv = to->attendees();
00557     Attendee::List::ConstIterator inIt;
00558     Attendee::List::ConstIterator evIt;
00559     for ( inIt = attendeesIn.begin(); inIt != attendeesIn.end(); ++inIt ) {
00560       Attendee *attIn = *inIt;
00561       bool found = false;
00562       for ( evIt = attendeesEv.begin(); evIt != attendeesEv.end(); ++evIt ) {
00563         Attendee *attEv = *evIt;
00564         if (attIn->email().lower()==attEv->email().lower()) {
00565           //update attendee-info
00566           kdDebug(5800) << "Scheduler::acceptTransaction update attendee" << endl;
00567           attEv->setStatus(attIn->status());
00568           attEv->setDelegate(attIn->delegate());
00569           attEv->setDelegator(attIn->delegator());
00570           ret = true;
00571           found = true;
00572         }
00573       }
00574       if ( !found && attIn->status() != Attendee::Declined )
00575         attendeesNew.append( attIn );
00576     }
00577 
00578     bool attendeeAdded = false;
00579     for ( Attendee::List::ConstIterator it = attendeesNew.constBegin(); it != attendeesNew.constEnd(); ++it ) {
00580       Attendee* attNew = *it;
00581       QString msg = i18n("%1 wants to attend %2 but was not invited.").arg( attNew->fullName() )
00582           .arg( ev ? ev->summary() : to->summary() );
00583       if ( !attNew->delegator().isEmpty() )
00584         msg = i18n("%1 wants to attend %2 on behalf of %3.").arg( attNew->fullName() )
00585             .arg( ev ? ev->summary() : to->summary() )
00586             .arg( attNew->delegator() );
00587       if ( KMessageBox::questionYesNo( 0, msg, i18n("Uninvited attendee"),
00588            KGuiItem(i18n("Accept Attendance")), KGuiItem(i18n("Reject Attendance")) )
00589            != KMessageBox::Yes )
00590       {
00591         KCal::Incidence *cancel = dynamic_cast<Incidence*>( incidence );
00592         if ( cancel )
00593           cancel->addComment( i18n( "The organizer rejected your attendance at this meeting." ) );
00594         performTransaction( cancel ? cancel : incidence, Scheduler::Cancel, attNew->fullName() );
00595         delete cancel;
00596         continue;
00597       }
00598 
00599       Attendee *a = new Attendee( attNew->name(), attNew->email(), attNew->RSVP(),
00600                                   attNew->status(), attNew->role(), attNew->uid() );
00601       a->setDelegate( attNew->delegate() );
00602       a->setDelegator( attNew->delegator() );
00603       if ( ev )
00604         ev->addAttendee( a );
00605       else if ( to )
00606         to->addAttendee( a );
00607       ret = true;
00608       attendeeAdded = true;
00609     }
00610 
00611     // send update about new participants
00612     if ( attendeeAdded ) {
00613       bool sendMail = false;
00614       if ( ev || to ) {
00615         if ( KMessageBox::questionYesNo( 0, i18n( "An attendee was added to the incidence. "
00616                                                   "Do you want to email the attendees an update message?" ),
00617                                          i18n( "Attendee Added" ), i18n( "Send Messages" ),
00618                                          i18n( "Do Not Send" ) ) == KMessageBox::Yes ) {
00619           sendMail = true;
00620         }
00621       }
00622 
00623       if ( ev ) {
00624         ev->setRevision( ev->revision() + 1 );
00625         if ( sendMail )
00626           performTransaction( ev, Scheduler::Request );
00627       }
00628       if ( to ) {
00629         to->setRevision( to->revision() + 1 );
00630         if ( sendMail )
00631           performTransaction( to, Scheduler::Request );
00632       }
00633     }
00634 
00635     if ( ret ) {
00636       // We set at least one of the attendees, so the incidence changed
00637       // Note: This should not result in a sequence number bump
00638       if ( ev )
00639         ev->updated();
00640       else if ( to )
00641         to->updated();
00642     }
00643     if ( to ) {
00644       // for VTODO a REPLY can be used to update the completion status of
00645       // a task. see RFC2446 3.4.3
00646       Todo *update = dynamic_cast<Todo*> ( incidence );
00647       Q_ASSERT( update );
00648       if ( update && ( to->percentComplete() != update->percentComplete() ) ) {
00649         to->setPercentComplete( update->percentComplete() );
00650         to->updated();
00651       }
00652     }
00653   } else
00654     kdError(5800) << "No incidence for scheduling\n";
00655   if (ret) deleteTransaction(incidence);
00656   return ret;
00657 }
00658 
00659 bool Scheduler::acceptRefresh(IncidenceBase *incidence,ScheduleMessage::Status /* status */)
00660 {
00661   // handled in korganizer's IncomingDialog
00662   deleteTransaction(incidence);
00663   return false;
00664 }
00665 
00666 bool Scheduler::acceptCounter(IncidenceBase *incidence,ScheduleMessage::Status /* status */)
00667 {
00668   deleteTransaction(incidence);
00669   return false;
00670 }
00671 
00672 bool Scheduler::acceptFreeBusy(IncidenceBase *incidence, Method method)
00673 {
00674   if ( !d->mFreeBusyCache ) {
00675     kdError() << "KCal::Scheduler: no FreeBusyCache." << endl;
00676     return false;
00677   }
00678 
00679   FreeBusy *freebusy = static_cast<FreeBusy *>(incidence);
00680 
00681   kdDebug(5800) << "acceptFreeBusy:: freeBusyDirName: " << freeBusyDir() << endl;
00682 
00683   Person from;
00684   if(method == Scheduler::Publish) {
00685     from = freebusy->organizer();
00686   }
00687   if((method == Scheduler::Reply) && (freebusy->attendeeCount() == 1)) {
00688     Attendee *attendee = freebusy->attendees().first();
00689     from = attendee->email();
00690   }
00691 
00692   if ( !d->mFreeBusyCache->saveFreeBusy( freebusy, from ) ) return false;
00693 
00694   deleteTransaction(incidence);
00695   return true;
00696 }
KDE Home | KDE Accessibility Home | Description of Access Keys