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 <kstandarddirs.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,Method method,ScheduleMessage::Status status)
00097 {
00098   kdDebug(5800) << "Scheduler::acceptTransaction, method="
00099                 << methodName( method ) << endl;
00100 
00101   switch (method) {
00102     case Publish:
00103       return acceptPublish(incidence, status, method);
00104     case Request:
00105       return acceptRequest(incidence, status);
00106     case Add:
00107       return acceptAdd(incidence, status);
00108     case Cancel:
00109       return acceptCancel(incidence, status);
00110     case Declinecounter:
00111       return acceptDeclineCounter(incidence, status);
00112     case Reply:
00113       return acceptReply(incidence, status, method);
00114     case Refresh:
00115       return acceptRefresh(incidence, status);
00116     case Counter:
00117       return acceptCounter(incidence, status);
00118     default:
00119       break;
00120   }
00121   deleteTransaction(incidence);
00122   return false;
00123 }
00124 
00125 QString Scheduler::methodName(Method method)
00126 {
00127   switch (method) {
00128     case Publish:
00129       return QString::fromLatin1("Publish");
00130     case Request:
00131       return QString::fromLatin1("Request");
00132     case Refresh:
00133       return QString::fromLatin1("Refresh");
00134     case Cancel:
00135       return QString::fromLatin1("Cancel");
00136     case Add:
00137       return QString::fromLatin1("Add");
00138     case Reply:
00139       return QString::fromLatin1("Reply");
00140     case Counter:
00141       return QString::fromLatin1("Counter");
00142     case Declinecounter:
00143       return QString::fromLatin1("Decline Counter");
00144     default:
00145       return QString::fromLatin1("Unknown");
00146   }
00147 }
00148 
00149 QString Scheduler::translatedMethodName(Method method)
00150 {
00151   switch (method) {
00152     case Publish:
00153       return i18n("Publish");
00154     case Request:
00155       return i18n("Request");
00156     case Refresh:
00157       return i18n("Refresh");
00158     case Cancel:
00159       return i18n("Cancel");
00160     case Add:
00161       return i18n("Add");
00162     case Reply:
00163       return i18n("Reply");
00164     case Counter:
00165       return i18n("counter proposal","Counter");
00166     case Declinecounter:
00167       return i18n("decline counter proposal","Decline Counter");
00168     default:
00169       return i18n("Unknown");
00170   }
00171 }
00172 
00173 bool Scheduler::deleteTransaction(IncidenceBase *)
00174 {
00175   return true;
00176 }
00177 
00178 bool Scheduler::acceptPublish( IncidenceBase *newIncBase,
00179                                ScheduleMessage::Status status, Method method )
00180 {
00181   if( newIncBase->type() == "FreeBusy" ) {
00182     return acceptFreeBusy( newIncBase, method );
00183   }
00184 
00185   bool res = false;
00186   kdDebug(5800) << "Scheduler::acceptPublish, status="
00187             << ScheduleMessage::statusName( status ) << endl;
00188   Incidence *newInc = static_cast<Incidence *>( newIncBase );
00189   Incidence *calInc = mCalendar->incidence( newIncBase->uid() );
00190   switch ( status ) {
00191     case ScheduleMessage::Unknown:
00192     case ScheduleMessage::PublishNew:
00193     case ScheduleMessage::PublishUpdate:
00194       res = true;
00195       if ( calInc ) {
00196         if ( (newInc->revision() > calInc->revision()) ||
00197              (newInc->revision() == calInc->revision() &&
00198                newInc->lastModified() > calInc->lastModified() ) ) {
00199           mCalendar->deleteIncidence( calInc );
00200         } else
00201           res = false;
00202       }
00203       if ( res )
00204         mCalendar->addIncidence( newInc );
00205       break;
00206     case ScheduleMessage::Obsolete:
00207       res = true;
00208       break;
00209     default:
00210       break;
00211   }
00212   deleteTransaction( newIncBase );
00213   return res;
00214 }
00215 
00216 bool Scheduler::acceptRequest(IncidenceBase *newIncBase, ScheduleMessage::Status /* status */)
00217 {
00218   if (newIncBase->type()=="FreeBusy") {
00219     // reply to this request is handled in korganizer's incomingdialog
00220     return true;
00221   }
00222   Incidence *newInc = dynamic_cast<Incidence *>( newIncBase );
00223   if ( newInc ) {
00224     bool res = true;
00225     Incidence *exInc = mCalendar->incidenceFromSchedulingID( newIncBase->uid() );
00226     if ( exInc ) {
00227       res = false;
00228       if ( (newInc->revision() > exInc->revision()) ||
00229            (newInc->revision() == exInc->revision() &&
00230              newInc->lastModified()>exInc->lastModified()) ) {
00231         mCalendar->deleteIncidence( exInc );
00232         res = true;
00233       }
00234     }
00235     if ( res ) {
00236       // Move the uid to be the schedulingID and make a unique UID
00237       newInc->setSchedulingID( newInc->uid() );
00238       newInc->setUid( CalFormat::createUniqueId() );
00239 
00240       mCalendar->addIncidence(newInc);
00241     }
00242     deleteTransaction( newIncBase );
00243     return res;
00244   }
00245   return false;
00246 }
00247 
00248 bool Scheduler::acceptAdd(IncidenceBase *incidence,ScheduleMessage::Status /* status */)
00249 {
00250   deleteTransaction(incidence);
00251   return false;
00252 }
00253 
00254 bool Scheduler::acceptCancel(IncidenceBase *incidence,ScheduleMessage::Status /* status */)
00255 {
00256   bool ret = false;
00257   const IncidenceBase *toDelete = mCalendar->incidenceFromSchedulingID( incidence->uid() );
00258   if ( toDelete ) {
00259     Event *even = mCalendar->event(toDelete->uid());
00260     if (even) {
00261       mCalendar->deleteEvent(even);
00262       ret = true;
00263     } else {
00264       Todo *todo = mCalendar->todo(toDelete->uid());
00265       if (todo) {
00266         mCalendar->deleteTodo(todo);
00267         ret = true;
00268       }
00269     }
00270   }
00271   deleteTransaction(incidence);
00272   return ret;
00273 }
00274 
00275 bool Scheduler::acceptDeclineCounter(IncidenceBase *incidence,ScheduleMessage::Status /* status */)
00276 {
00277   deleteTransaction(incidence);
00278   return false;
00279 }
00280 
00281 //bool Scheduler::acceptFreeBusy(Incidence *incidence,ScheduleMessage::Status status)
00282 //{
00283 //  deleteTransaction(incidence);
00284 //  return false;
00285 //}
00286 
00287 bool Scheduler::acceptReply(IncidenceBase *incidence,ScheduleMessage::Status /* status */, Method method)
00288 {
00289   if(incidence->type()=="FreeBusy") {
00290     return acceptFreeBusy(incidence, method);
00291   }
00292   bool ret = false;
00293   Event *ev = mCalendar->event(incidence->uid());
00294   Todo *to = mCalendar->todo(incidence->uid());
00295   if (ev || to) {
00296     //get matching attendee in calendar
00297     kdDebug(5800) << "Scheduler::acceptTransaction match found!" << endl;
00298     Attendee::List attendeesIn = incidence->attendees();
00299     Attendee::List attendeesEv;
00300     if (ev) attendeesEv = ev->attendees();
00301     if (to) attendeesEv = to->attendees();
00302     Attendee::List::ConstIterator inIt;
00303     Attendee::List::ConstIterator evIt;
00304     for ( inIt = attendeesIn.begin(); inIt != attendeesIn.end(); ++inIt ) {
00305       Attendee *attIn = *inIt;
00306       for ( evIt = attendeesEv.begin(); evIt != attendeesEv.end(); ++evIt ) {
00307         Attendee *attEv = *evIt;
00308         if (attIn->email().lower()==attEv->email().lower()) {
00309           //update attendee-info
00310           kdDebug(5800) << "Scheduler::acceptTransaction update attendee" << endl;
00311           attEv->setStatus(attIn->status());
00312           ret = true;
00313         }
00314       }
00315     }
00316     if ( ret ) {
00317       // We set at least one of the attendees, so the incidence changed
00318       // Note: This should not result in a sequence number bump
00319       if ( ev )
00320         ev->updated();
00321       else if ( to )
00322         to->updated();
00323     }
00324     if ( to ) {
00325       // for VTODO a REPLY can be used to update the completion status of 
00326       // a task. see RFC2446 3.4.3
00327       Todo *update = dynamic_cast<Todo*> ( incidence );
00328       Q_ASSERT( update );
00329       if ( update && ( to->percentComplete() != update->percentComplete() ) ) {
00330         to->setPercentComplete( update->percentComplete() );
00331         to->updated();
00332       }
00333     }
00334   } else
00335     kdError(5800) << "No incidence for scheduling\n";
00336   if (ret) deleteTransaction(incidence);
00337   return ret;
00338 }
00339 
00340 bool Scheduler::acceptRefresh(IncidenceBase *incidence,ScheduleMessage::Status /* status */)
00341 {
00342   // handled in korganizer's IncomingDialog
00343   deleteTransaction(incidence);
00344   return false;
00345 }
00346 
00347 bool Scheduler::acceptCounter(IncidenceBase *incidence,ScheduleMessage::Status /* status */)
00348 {
00349   deleteTransaction(incidence);
00350   return false;
00351 }
00352 
00353 bool Scheduler::acceptFreeBusy(IncidenceBase *incidence, Method method)
00354 {
00355   if ( !d->mFreeBusyCache ) {
00356     kdError() << "KCal::Scheduler: no FreeBusyCache." << endl;
00357     return false;
00358   }
00359 
00360   FreeBusy *freebusy = static_cast<FreeBusy *>(incidence);
00361 
00362   kdDebug(5800) << "acceptFreeBusy:: freeBusyDirName: " << freeBusyDir() << endl;
00363 
00364   Person from;
00365   if(method == Scheduler::Publish) {
00366     from = freebusy->organizer();
00367   }
00368   if((method == Scheduler::Reply) && (freebusy->attendeeCount() == 1)) {
00369     Attendee *attendee = freebusy->attendees().first();
00370     from = attendee->email();
00371   }
00372 
00373   if ( !d->mFreeBusyCache->saveFreeBusy( freebusy, from ) ) return false;
00374 
00375   deleteTransaction(incidence);
00376   return true;
00377 }
KDE Home | KDE Accessibility Home | Description of Access Keys