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

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
  • kcalcore
  • kcalutils
  • kholidays
  • kimap
  • kioslave
  •   imap4
  •   mbox
  •   nntp
  • kldap
  • kmbox
  • 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.3
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