00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022 #include <klocale.h>
00023 #include <kdebug.h>
00024 #include <kstandarddirs.h>
00025 #include <kmessagebox.h>
00026
00027 #include "event.h"
00028 #include "todo.h"
00029 #include "freebusy.h"
00030 #include "icalformat.h"
00031 #include "calendar.h"
00032 #include "freebusycache.h"
00033
00034 #include "scheduler.h"
00035
00036 using namespace KCal;
00037
00038 ScheduleMessage::ScheduleMessage(IncidenceBase *incidence,int method,ScheduleMessage::Status status)
00039 {
00040 mIncidence = incidence;
00041 mMethod = method;
00042 mStatus = status;
00043 }
00044
00045 QString ScheduleMessage::statusName(ScheduleMessage::Status status)
00046 {
00047 switch (status) {
00048 case PublishUpdate:
00049 return i18n("Updated Publish");
00050 case PublishNew:
00051 return i18n("Publish");
00052 case Obsolete:
00053 return i18n("Obsolete");
00054 case RequestNew:
00055 return i18n("New Request");
00056 case RequestUpdate:
00057 return i18n("Updated Request");
00058 default:
00059 return i18n("Unknown Status: %1").arg(QString::number(status));
00060 }
00061 }
00062
00063 struct Scheduler::Private
00064 {
00065 Private() : mFreeBusyCache( 0 ) {}
00066
00067 FreeBusyCache *mFreeBusyCache;
00068 };
00069
00070 Scheduler::Scheduler(Calendar *calendar)
00071 {
00072 mCalendar = calendar;
00073 mFormat = new ICalFormat();
00074 mFormat->setTimeZone( calendar->timeZoneId(), !calendar->isLocalTime() );
00075
00076 d = new Private;
00077 }
00078
00079 Scheduler::~Scheduler()
00080 {
00081 delete d;
00082
00083 delete mFormat;
00084 }
00085
00086 void Scheduler::setFreeBusyCache( FreeBusyCache *c )
00087 {
00088 d->mFreeBusyCache = c;
00089 }
00090
00091 FreeBusyCache *Scheduler::freeBusyCache() const
00092 {
00093 return d->mFreeBusyCache;
00094 }
00095
00096 bool Scheduler::acceptTransaction( IncidenceBase *incidence,
00097 Method method,
00098 ScheduleMessage::Status status,
00099 const QString &attendee )
00100 {
00101 kdDebug(5800) << "Scheduler::acceptTransaction, method="
00102 << methodName( method ) << endl;
00103
00104 switch (method) {
00105 case Publish:
00106 return acceptPublish(incidence, status, method);
00107 case Request:
00108 return acceptRequest( incidence, status, attendee );
00109 case Add:
00110 return acceptAdd(incidence, status);
00111 case Cancel:
00112 return acceptCancel(incidence, status);
00113 case Declinecounter:
00114 return acceptDeclineCounter(incidence, status);
00115 case Reply:
00116 return acceptReply(incidence, status, method);
00117 case Refresh:
00118 return acceptRefresh(incidence, status);
00119 case Counter:
00120 return acceptCounter(incidence, status);
00121 default:
00122 deleteTransaction(incidence);
00123 return false;
00124 }
00125 deleteTransaction(incidence);
00126 return false;
00127 }
00128
00129 QString Scheduler::methodName(Method method)
00130 {
00131 switch (method) {
00132 case Publish:
00133 return QString::fromLatin1("Publish");
00134 case Request:
00135 return QString::fromLatin1("Request");
00136 case Refresh:
00137 return QString::fromLatin1("Refresh");
00138 case Cancel:
00139 return QString::fromLatin1("Cancel");
00140 case Add:
00141 return QString::fromLatin1("Add");
00142 case Reply:
00143 return QString::fromLatin1("Reply");
00144 case Counter:
00145 return QString::fromLatin1("Counter");
00146 case Declinecounter:
00147 return QString::fromLatin1("Decline Counter");
00148 default:
00149 return QString::fromLatin1("Unknown");
00150 }
00151 }
00152
00153 QString Scheduler::translatedMethodName(Method method)
00154 {
00155 switch (method) {
00156 case Publish:
00157 return i18n("Publish");
00158 case Request:
00159 return i18n("Request");
00160 case Refresh:
00161 return i18n("Refresh");
00162 case Cancel:
00163 return i18n("Cancel");
00164 case Add:
00165 return i18n("Add");
00166 case Reply:
00167 return i18n("Reply");
00168 case Counter:
00169 return i18n("counter proposal","Counter");
00170 case Declinecounter:
00171 return i18n("decline counter proposal","Decline Counter");
00172 default:
00173 return i18n("Unknown");
00174 }
00175 }
00176
00177 bool Scheduler::deleteTransaction(IncidenceBase *)
00178 {
00179 return true;
00180 }
00181
00182 bool Scheduler::acceptPublish( IncidenceBase *incidence,
00183 ScheduleMessage::Status status, Method method )
00184 {
00185 if( incidence->type() == "FreeBusy" ) {
00186 return acceptFreeBusy( incidence, method );
00187 }
00188 kdDebug(5800) << "Scheduler::acceptPublish, status="
00189 << ScheduleMessage::statusName( status ) << endl;
00190 Incidence *inc = static_cast<Incidence *>( incidence );
00191 Event *even = mCalendar->event( incidence->uid() );
00192 switch ( status ) {
00193 case ScheduleMessage::Unknown:
00194 case ScheduleMessage::PublishNew:
00195 case ScheduleMessage::PublishUpdate:
00196 if ( even ) {
00197 if ( even->revision() <= inc->revision() ) {
00198 if ( even->revision() == inc->revision() &&
00199 even->lastModified() > inc->lastModified() ) {
00200 deleteTransaction( incidence );
00201 return false;
00202 }
00203 mCalendar->deleteEvent( even );
00204 } else {
00205 deleteTransaction( incidence );
00206 return false;
00207 }
00208 }
00209 mCalendar->addIncidence( inc );
00210 deleteTransaction( incidence );
00211 return true;
00212 case ScheduleMessage::Obsolete:
00213 return true;
00214 default:
00215 deleteTransaction( incidence );
00216 return false;
00217 }
00218 }
00219
00220 bool Scheduler::acceptRequest( IncidenceBase *incidence,
00221 ScheduleMessage::Status status,
00222 const QString &attendee )
00223 {
00224 Incidence *inc = static_cast<Incidence *>(incidence);
00225 if (inc->type()=="FreeBusy") {
00226
00227 return true;
00228 }
00229
00230 const Incidence::List existingIncidences = mCalendar->incidencesFromSchedulingID( inc->uid() );
00231 kdDebug(5800) << "Scheduler::acceptRequest status=" << ScheduleMessage::statusName( status ) << ": found " << existingIncidences.count() << " incidences with schedulingID " << inc->schedulingID() << endl;
00232 Incidence::List::ConstIterator incit = existingIncidences.begin();
00233 for ( ; incit != existingIncidences.end() ; ++incit ) {
00234 Incidence* const i = *incit;
00235 kdDebug(5800) << "Considering this found event ("
00236 << ( i->isReadOnly() ? "readonly" : "readwrite" )
00237 << ") :" << mFormat->toString( i ) << endl;
00238
00239 if ( i->isReadOnly() )
00240 continue;
00241 if ( i->revision() <= inc->revision() ) {
00242
00243 bool isUpdate = true;
00244
00245
00246
00247
00248
00249 kdDebug(5800) << "looking in " << i->uid() << "'s attendees" << endl;
00250
00251
00252
00253 const KCal::Attendee::List attendees = i->attendees();
00254 KCal::Attendee::List::ConstIterator ait;
00255 for ( ait = attendees.begin(); ait != attendees.end(); ++ait ) {
00256 if( (*ait)->email() == attendee && (*ait)->status() == Attendee::NeedsAction ) {
00257
00258
00259 kdDebug(5800) << "ignoring " << i->uid() << " since I'm still NeedsAction there" << endl;
00260 isUpdate = false;
00261 break;
00262 }
00263 }
00264 if ( isUpdate ) {
00265 if ( i->revision() == inc->revision() &&
00266 i->lastModified() > inc->lastModified() ) {
00267
00268 kdDebug(5800) << "This isn't an update - the found incidence was modified more recently" << endl;
00269 deleteTransaction(incidence);
00270 return false;
00271 }
00272 kdDebug(5800) << "replacing existing incidence " << i->uid() << endl;
00273 mCalendar->deleteIncidence( i );
00274 break;
00275 }
00276 } else {
00277
00278 kdDebug(5800) << "This isn't an update - the found incidence has a bigger revision number" << endl;
00279 deleteTransaction(incidence);
00280 return false;
00281 }
00282 }
00283
00284
00285 inc->setSchedulingID( inc->uid() );
00286 inc->setUid( CalFormat::createUniqueId() );
00287
00288
00289 if ( existingIncidences.count() > 0 || inc->revision() == 0 ||
00290 KMessageBox::warningYesNo( 0,
00291 i18n("The event, task or journal to be updated could not be found. "
00292 "Maybe it has already been deleted, or the calendar that "
00293 "contains it is disabled. Press continue to create a new "
00294 "one or 'throw away' to discard this update." ),
00295 i18n("Discard this update?"), i18n("Store"), i18n("Throw away") ) == KMessageBox::Yes ) {
00296 kdDebug(5800) << "Storing new incidence with scheduling uid=" << inc->schedulingID() << " and uid=" << inc->uid() << endl;
00297 mCalendar->addIncidence(inc);
00298 }
00299 deleteTransaction(incidence);
00300 return true;
00301 }
00302
00303 bool Scheduler::acceptAdd(IncidenceBase *incidence,ScheduleMessage::Status )
00304 {
00305 deleteTransaction(incidence);
00306 return false;
00307 }
00308
00309 bool Scheduler::acceptCancel(IncidenceBase *incidence,ScheduleMessage::Status )
00310 {
00311 bool ret = false;
00312 const IncidenceBase *toDelete = mCalendar->incidenceFromSchedulingID( incidence->uid() );
00313 if ( !toDelete ) {
00314 Incidence *inc = static_cast<Incidence *>(incidence);
00315 if ( inc->revision() > 0 )
00316 KMessageBox::error( 0,
00317 i18n("The event, task or journal to be canceled could not be found. "
00318 "Maybe it has already been deleted, or the calendar that "
00319 "contains it is disabled." ) );
00320 } else {
00321 Event *even = mCalendar->event(toDelete->uid());
00322 if (even) {
00323 mCalendar->deleteEvent(even);
00324 ret = true;
00325 } else {
00326 Todo *todo = mCalendar->todo(toDelete->uid());
00327 if (todo) {
00328 mCalendar->deleteTodo(todo);
00329 ret = true;
00330 }
00331 }
00332 }
00333 deleteTransaction(incidence);
00334 return ret;
00335 }
00336
00337 bool Scheduler::acceptDeclineCounter(IncidenceBase *incidence,ScheduleMessage::Status )
00338 {
00339 deleteTransaction(incidence);
00340 return false;
00341 }
00342
00343
00344
00345
00346
00347
00348
00349 bool Scheduler::acceptReply(IncidenceBase *incidence,ScheduleMessage::Status , Method method)
00350 {
00351 if(incidence->type()=="FreeBusy") {
00352 return acceptFreeBusy(incidence, method);
00353 }
00354 bool ret = false;
00355 Event *ev = mCalendar->event(incidence->uid());
00356 Todo *to = mCalendar->todo(incidence->uid());
00357 if (ev || to) {
00358
00359 kdDebug(5800) << "Scheduler::acceptTransaction match found!" << endl;
00360 Attendee::List attendeesIn = incidence->attendees();
00361 Attendee::List attendeesEv;
00362 if (ev) attendeesEv = ev->attendees();
00363 if (to) attendeesEv = to->attendees();
00364 Attendee::List::ConstIterator inIt;
00365 Attendee::List::ConstIterator evIt;
00366 for ( inIt = attendeesIn.begin(); inIt != attendeesIn.end(); ++inIt ) {
00367 Attendee *attIn = *inIt;
00368 for ( evIt = attendeesEv.begin(); evIt != attendeesEv.end(); ++evIt ) {
00369 Attendee *attEv = *evIt;
00370 if (attIn->email().lower()==attEv->email().lower()) {
00371
00372 kdDebug(5800) << "Scheduler::acceptTransaction update attendee" << endl;
00373 attEv->setStatus(attIn->status());
00374 ret = true;
00375 }
00376 }
00377 }
00378 if ( !ret ) {
00379
00380 for ( inIt = attendeesIn.begin(); inIt != attendeesIn.end(); ++inIt ) {
00381 Attendee* old = (*inIt);
00382 Attendee* a = new Attendee( old->name(), old->email(), false,
00383 old->status(), Attendee::OptParticipant );
00384 if ( ev )
00385 ev->addAttendee( a, false );
00386 else
00387 to->addAttendee( a, false );
00388 ret = true;
00389 }
00390 }
00391
00392 if ( ret ) {
00393
00394
00395 if ( ev )
00396 ev->updated();
00397 else if ( to )
00398 to->updated();
00399 }
00400 if ( to ) {
00401
00402
00403 Todo *update = dynamic_cast<Todo*> ( incidence );
00404 Q_ASSERT( update );
00405 if ( update && ( to->percentComplete() != update->percentComplete() ) ) {
00406 to->setPercentComplete( update->percentComplete() );
00407 to->updated();
00408 }
00409 }
00410 } else
00411 kdError(5800) << "No incidence for scheduling\n";
00412 if (ret) deleteTransaction(incidence);
00413 return ret;
00414 }
00415
00416 bool Scheduler::acceptRefresh(IncidenceBase *incidence,ScheduleMessage::Status )
00417 {
00418
00419 deleteTransaction(incidence);
00420 return false;
00421 }
00422
00423 bool Scheduler::acceptCounter(IncidenceBase *incidence,ScheduleMessage::Status )
00424 {
00425 deleteTransaction(incidence);
00426 return false;
00427 }
00428
00429 bool Scheduler::acceptFreeBusy(IncidenceBase *incidence, Method method)
00430 {
00431 if ( !d->mFreeBusyCache ) {
00432 kdError() << "KCal::Scheduler: no FreeBusyCache." << endl;
00433 return false;
00434 }
00435
00436 FreeBusy *freebusy = static_cast<FreeBusy *>(incidence);
00437
00438 kdDebug(5800) << "acceptFreeBusy:: freeBusyDirName: " << freeBusyDir() << endl;
00439
00440 Person from;
00441 if(method == Scheduler::Publish) {
00442 from = freebusy->organizer();
00443 }
00444 if((method == Scheduler::Reply) && (freebusy->attendeeCount() == 1)) {
00445 Attendee *attendee = freebusy->attendees().first();
00446 from = attendee->email();
00447 }
00448
00449 if ( !d->mFreeBusyCache->saveFreeBusy( freebusy, from ) ) return false;
00450
00451 deleteTransaction(incidence);
00452 return true;
00453 }