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