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