• Skip to content
  • Skip to link menu
KDE 4.5 API Reference
  • KDE API Reference
  • KDE-PIM Libraries
  • Sitemap
  • Contact Us
 

KCal Library

scheduler.cpp

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

KCal Library

Skip menu "KCal Library"
  • Main Page
  • Namespace List
  • Class Hierarchy
  • Alphabetical List
  • Class List
  • File List
  • Namespace Members
  • Class Members
  • Related Pages

KDE-PIM Libraries

Skip menu "KDE-PIM Libraries"
  • akonadi
  •   contact
  •   kmime
  • kabc
  • kblog
  • kcal
  • kholidays
  • kimap
  • kioslave
  •   imap4
  •   mbox
  •   nntp
  • kldap
  • kmime
  • kontactinterface
  • kpimidentities
  • kpimtextedit
  •   richtextbuilders
  • kpimutils
  • kresources
  • ktnef
  • kxmlrpcclient
  • mailtransport
  • microblog
  • qgpgme
  • syndication
  •   atom
  •   rdf
  •   rss2
Generated for KDE-PIM Libraries by doxygen 1.7.1
This website is maintained by Adriaan de Groot and Allen Winter.
KDE® and the K Desktop Environment® logo are registered trademarks of KDE e.V. | Legal