korganizer

kogroupware.cpp

00001 /*
00002   This file is part of the Groupware/KOrganizer integration.
00003 
00004   Requires the Qt and KDE widget libraries, available at no cost at
00005   http://www.trolltech.com and http://www.kde.org respectively
00006 
00007   Copyright (c) 2002-2004 Klarälvdalens Datakonsult AB
00008         <info@klaralvdalens-datakonsult.se>
00009 
00010   This program is free software; you can redistribute it and/or modify
00011   it under the terms of the GNU General Public License as published by
00012   the Free Software Foundation; either version 2 of the License, or
00013   (at your option) any later version.
00014 
00015   This program is distributed in the hope that it will be useful,
00016   but WITHOUT ANY WARRANTY; without even the implied warranty of
00017   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
00018   GNU General Public License for more details.
00019 
00020   You should have received a copy of the GNU General Public License
00021   along with this program; if not, write to the Free Software
00022   Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
00023   MA  02110-1301, USA.
00024 
00025   In addition, as a special exception, the copyright holders give
00026   permission to link the code of this program with any edition of
00027   the Qt library by Trolltech AS, Norway (or with modified versions
00028   of Qt that use the same license as Qt), and distribute linked
00029   combinations including the two.  You must obey the GNU General
00030   Public License in all respects for all of the code used other than
00031   Qt.  If you modify this file, you may extend this exception to
00032   your version of the file, but you are not obligated to do so.  If
00033   you do not wish to do so, delete this exception statement from
00034   your version.
00035 */
00036 
00037 #include "kogroupware.h"
00038 #include "freebusymanager.h"
00039 #include "calendarview.h"
00040 #include "mailscheduler.h"
00041 #include "koprefs.h"
00042 #include "koincidenceeditor.h"
00043 #include <libemailfunctions/email.h>
00044 #include <libkcal/attendee.h>
00045 #include <libkcal/calhelper.h>
00046 #include <libkcal/journal.h>
00047 #include <libkcal/incidenceformatter.h>
00048 #include <kdebug.h>
00049 #include <kmessagebox.h>
00050 #include <kstandarddirs.h>
00051 #include <kdirwatch.h>
00052 #include <qfile.h>
00053 #include <qregexp.h>
00054 #include <qdir.h>
00055 #include <qtimer.h>
00056 
00057 FreeBusyManager *KOGroupware::mFreeBusyManager = 0;
00058 
00059 KOGroupware *KOGroupware::mInstance = 0;
00060 
00061 KOGroupware *KOGroupware::create( CalendarView *view,
00062                                   KCal::CalendarResources *calendar )
00063 {
00064   if( !mInstance )
00065     mInstance = new KOGroupware( view, calendar );
00066   return mInstance;
00067 }
00068 
00069 void KOGroupware::destroy()
00070 {
00071   delete mInstance;
00072   mInstance = 0;
00073   mFreeBusyManager = 0; // mFreeBusyManager is already deleted when mInstance is deleted
00074 }
00075 
00076 KOGroupware *KOGroupware::instance()
00077 {
00078   // Doesn't create, that is the task of create()
00079   Q_ASSERT( mInstance );
00080   return mInstance;
00081 }
00082 
00083 
00084 KOGroupware::KOGroupware( CalendarView* view, KCal::CalendarResources* cal )
00085    : QObject( 0, "kmgroupware_instance" ), mView( view ), mCalendar( cal ), mDoNotNotify( false )
00086 {
00087   // Set up the dir watch of the three incoming dirs
00088   KDirWatch* watcher = KDirWatch::self();
00089   watcher->addDir( locateLocal( "data", "korganizer/income.accepted/" ) );
00090   watcher->addDir( locateLocal( "data", "korganizer/income.tentative/" ) );
00091   watcher->addDir( locateLocal( "data", "korganizer/income.counter/" ) );
00092   watcher->addDir( locateLocal( "data", "korganizer/income.cancel/" ) );
00093   watcher->addDir( locateLocal( "data", "korganizer/income.reply/" ) );
00094   watcher->addDir( locateLocal( "data", "korganizer/income.delegated/" ) );
00095   connect( watcher, SIGNAL( dirty( const QString& ) ),
00096            this, SLOT( incomingDirChanged( const QString& ) ) );
00097   // Now set the ball rolling
00098   QTimer::singleShot( 0, this, SLOT(initialCheckForChanges()) );
00099 
00100   // Initialize
00101   lastUsedDialogAnswer = KMessageBox::Yes;
00102 }
00103 
00104 void KOGroupware::initialCheckForChanges()
00105 {
00106   incomingDirChanged( locateLocal( "data", "korganizer/income.accepted/" ) );
00107   incomingDirChanged( locateLocal( "data", "korganizer/income.tentative/" ) );
00108   incomingDirChanged( locateLocal( "data", "korganizer/income.counter/" ) );
00109   incomingDirChanged( locateLocal( "data", "korganizer/income.cancel/" ) );
00110   incomingDirChanged( locateLocal( "data", "korganizer/income.reply/" ) );
00111   incomingDirChanged( locateLocal( "data", "korganizer/income.delegated/" ) );
00112 }
00113 
00114 void KOGroupware::slotViewNewIncidenceChanger( IncidenceChangerBase* changer )
00115 {
00116     // Call slot perhapsUploadFB if an incidence was added, changed or removed
00117     connect( changer, SIGNAL( incidenceAdded( Incidence* ) ),
00118              mFreeBusyManager, SLOT( slotPerhapsUploadFB() ) );
00119     connect( changer, SIGNAL( incidenceChanged( Incidence*, Incidence*, KOGlobals::WhatChanged ) ),
00120              mFreeBusyManager, SLOT( slotPerhapsUploadFB() ) );
00121     connect( changer, SIGNAL( incidenceDeleted( Incidence * ) ),
00122              mFreeBusyManager, SLOT( slotPerhapsUploadFB() ) );
00123 }
00124 
00125 FreeBusyManager *KOGroupware::freeBusyManager()
00126 {
00127   if ( !mFreeBusyManager ) {
00128     mFreeBusyManager = new FreeBusyManager( this, "freebusymanager" );
00129     mFreeBusyManager->setCalendar( mCalendar );
00130     connect( mCalendar, SIGNAL( calendarChanged() ),
00131              mFreeBusyManager, SLOT( slotPerhapsUploadFB() ) );
00132     connect( mView, SIGNAL( newIncidenceChanger( IncidenceChangerBase* ) ),
00133              this, SLOT( slotViewNewIncidenceChanger( IncidenceChangerBase* ) ) );
00134     slotViewNewIncidenceChanger( mView->incidenceChanger() );
00135   }
00136 
00137   return mFreeBusyManager;
00138 }
00139 
00140 void KOGroupware::incomingDirChanged( const QString& path )
00141 {
00142   const QString incomingDirName = locateLocal( "data","korganizer/" )
00143                                   + "income.";
00144   if ( !path.startsWith( incomingDirName ) ) {
00145     kdDebug(5850) << "incomingDirChanged: Wrong dir " << path << endl;
00146     return;
00147   }
00148   QString action = path.mid( incomingDirName.length() );
00149   while ( action.length() > 0 && action[ action.length()-1 ] == '/' )
00150     // Strip slashes at the end
00151     action.truncate( action.length()-1 );
00152 
00153   // Handle accepted invitations
00154   QDir dir( path );
00155   const QStringList files = dir.entryList( QDir::Files );
00156   if ( files.isEmpty() )
00157     // No more files here
00158     return;
00159 
00160   // Read the file and remove it
00161   QFile f( path + "/" + files[0] );
00162   if (!f.open(IO_ReadOnly)) {
00163     kdError(5850) << "Can't open file '" << files[0] << "'" << endl;
00164     return;
00165   }
00166   QTextStream t(&f);
00167   t.setEncoding( QTextStream::UnicodeUTF8 );
00168   QString receiver = KPIM::getFirstEmailAddress( t.readLine() );
00169   QString iCal = t.read();
00170 
00171   f.remove();
00172 
00173   ScheduleMessage *message = mFormat.parseScheduleMessage( mCalendar, iCal );
00174   if ( !message ) {
00175     QString errorMessage;
00176     if (mFormat.exception())
00177       errorMessage = i18n( "Error message: %1" ).arg( mFormat.exception()->message() );
00178     kdDebug(5850) << "MailScheduler::retrieveTransactions() Error parsing "
00179                   << errorMessage << endl;
00180     KMessageBox::detailedError( mView,
00181         i18n("Error while processing an invitation or update."),
00182         errorMessage );
00183     return;
00184   }
00185 
00186   KCal::Scheduler::Method method =
00187     static_cast<KCal::Scheduler::Method>( message->method() );
00188   KCal::ScheduleMessage::Status status = message->status();
00189   KCal::Incidence* incidence =
00190     dynamic_cast<KCal::Incidence*>( message->event() );
00191   if(!incidence) {
00192     delete message;
00193     return;
00194   }
00195   KCal::MailScheduler scheduler( mCalendar );
00196   if ( action.startsWith( "accepted" ) || action.startsWith( "tentative" ) ||
00197        action.startsWith( "delegated" ) || action.startsWith( "counter" ) ) {
00198     // Find myself and set my status. This can't be done in the scheduler,
00199     // since this does not know the choice I made in the KMail bpf
00200     KCal::Attendee::List attendees = incidence->attendees();
00201     KCal::Attendee::List::ConstIterator it;
00202     for ( it = attendees.begin(); it != attendees.end(); ++it ) {
00203       if( (*it)->email() == receiver ) {
00204         if ( action.startsWith( "accepted" ) )
00205           (*it)->setStatus( KCal::Attendee::Accepted );
00206         else if ( action.startsWith( "tentative" ) )
00207           (*it)->setStatus( KCal::Attendee::Tentative );
00208         else if ( KOPrefs::instance()->outlookCompatCounterProposals() && action.startsWith( "counter" ) )
00209           (*it)->setStatus( KCal::Attendee::Tentative );
00210         else if ( action.startsWith( "delegated" ) )
00211           (*it)->setStatus( KCal::Attendee::Delegated );
00212         break;
00213       }
00214     }
00215     if ( KOPrefs::instance()->outlookCompatCounterProposals() || !action.startsWith( "counter" ) ) {
00216       if ( scheduler.acceptTransaction( incidence, method, status, receiver ) ) {
00217         mCalendar->save();
00218       }
00219     }
00220   } else if ( action.startsWith( "cancel" ) ) {
00221     // Delete the old incidence, if one is present
00222     if ( scheduler.acceptTransaction( incidence, KCal::Scheduler::Cancel, status, receiver ) ) {
00223       mCalendar->save();
00224     }
00225   } else if ( action.startsWith( "reply" ) ) {
00226     if ( method != Scheduler::Counter ) {
00227       if ( scheduler.acceptTransaction( incidence, method, status ) ) {
00228         mCalendar->save();
00229       }
00230     } else {
00231       // accept counter proposal
00232       if ( scheduler.acceptCounterProposal( incidence ) ) {
00233         mCalendar->save();
00234         // send update to all attendees
00235         sendICalMessage( mView, Scheduler::Request, incidence, 0,
00236                          KOGlobals::INCIDENCEEDITED, false );
00237       }
00238     }
00239   } else {
00240     kdError(5850) << "Unknown incoming action " << action << endl;
00241   }
00242 
00243   if ( action.startsWith( "counter" ) ) {
00244     mView->editIncidence( incidence, QDate(), true );
00245     KOIncidenceEditor *tmp = mView->editorDialog( incidence );
00246     tmp->selectInvitationCounterProposal( true );
00247   }
00248   mView->updateView();
00249 }
00250 
00251 class KOInvitationFormatterHelper : public InvitationFormatterHelper
00252 {
00253   public:
00254     virtual QString generateLinkURL( const QString &id ) { return "kmail:groupware_request_" + id; }
00255 };
00256 
00257 // A string comparison that considers that null and empty are the same
00258 static bool stringCompare( const QString &s1, const QString &s2 )
00259 {
00260   return ( s1.isEmpty() && s2.isEmpty() ) || ( s1 == s2 );
00261 }
00262 
00263 static bool compareIncsExceptAttendees( Incidence *i1, Incidence *i2 )
00264 {
00265   if( i1->alarms().count() != i2->alarms().count() ) {
00266     return false; // no need to check further
00267   }
00268 
00269   Alarm::List::ConstIterator a1 = i1->alarms().begin();
00270   Alarm::List::ConstIterator a2 = i2->alarms().begin();
00271   for( ; a1 != i1->alarms().end() && a2 != i2->alarms().end(); ++a1, ++a2 ) {
00272     if( **a1 == **a2 ) {
00273       continue;
00274     } else {
00275       return false;
00276     }
00277   }
00278 
00279   bool recurrenceEqual = ( i1->recurrence() == 0 && i2->recurrence() == 0 );
00280   if ( !recurrenceEqual ) {
00281     recurrenceEqual = i1->recurrence() != 0 &&
00282                       i2->recurrence() != 0 &&
00283                       i2->recurrence() == i2->recurrence();
00284   }
00285 
00286   return
00287     recurrenceEqual &&
00288     i1->dtStart() == i2->dtStart() &&
00289     i1->organizer() == i2->organizer() &&
00290     i1->doesFloat() == i2->doesFloat() &&
00291     i1->duration() == i2->duration() &&
00292     i2->hasDuration() == i2->hasDuration() &&
00293     stringCompare( i1->description(), i2->description() ) &&
00294     stringCompare( i1->summary(), i2->summary() ) &&
00295     i1->categories() == i2->categories() &&
00296     i1->attachments() == i2->attachments() &&
00297     i1->secrecy() == i2->secrecy() &&
00298     i1->priority() == i2->priority() &&
00299     stringCompare( i1->location(), i2->location() );
00300 }
00301 
00302 static QStringList recipients( Attendee::List attendees )
00303 {
00304   QStringList attStrList;
00305   for ( Attendee::List::ConstIterator it = attendees.begin(); it != attendees.end(); ++it ) {
00306     attStrList << (*it)->fullName();
00307   }
00308   return attStrList;
00309 }
00310 
00311 /* This function sends mails if necessary, and makes sure the user really
00312  * want to change his calendar.
00313  *
00314  * Return true means accept the changes
00315  * Return false means revert the changes
00316  */
00317 bool KOGroupware::sendICalMessage( QWidget* parent,
00318                                    KCal::Scheduler::Method method,
00319                                    Incidence *incidence,
00320                                    Incidence *oldincidence,
00321                                    KOGlobals::HowChanged action,
00322                                    bool attendeeStatusChanged,
00323                                    bool useLastDialogAnswer )
00324 {
00325   // If there are no attendees, don't bother
00326   if ( incidence->attendees().isEmpty() )
00327     return true;
00328 
00329   bool isOrganizer = KOPrefs::instance()->thatIsMe( incidence->organizer().email() );
00330   int rc = 0;
00331   /*
00332    * There are two scenarios:
00333    * o "we" are the organizer, where "we" means any of the identities or mail
00334    *   addresses known to Kontact/PIM. If there are attendees, we need to mail
00335    *   them all, even if one or more of them are also "us". Otherwise there
00336    *   would be no way to invite a resource or our boss, other identities we
00337    *   also manage.
00338    * o "we: are not the organizer, which means we changed the completion status
00339    *   of a todo, or we changed our attendee status from, say, tentative to
00340    *   accepted. In both cases we only mail the organizer. All other changes
00341    *   bring us out of sync with the organizer, so we won't mail, if the user
00342    *   insists on applying them.
00343    */
00344 
00345   if ( isOrganizer ) {
00346     // We are the organizer. If there is more than one attendee, or if there is
00347     // only one, and it's not the same as the organizer, ask the user to send mail.
00348     if ( incidence->attendees().count() > 1
00349         || incidence->attendees().first()->email() != incidence->organizer().email() ) {
00350 
00351       QString txt;
00352       switch( action ) {
00353       case KOGlobals::INCIDENCEEDITED:
00354       {
00355         bool sendUpdate = true;
00356 
00357         Attendee::List attendees = incidence->attendees();
00358         Attendee::List::ConstIterator it;
00359 
00360         // create the list of attendees from the new incidence
00361         Attendee::List sameAtts;
00362         for ( it = attendees.begin(); it != attendees.end(); ++it ) {
00363           if ( (*it)->email() != incidence->organizer().email() ) { //skip organizer
00364             sameAtts << *it;
00365           }
00366         }
00367 
00368         if ( incidence->summary().isEmpty() ) {
00369           incidence->setSummary( i18n( "<No summary given>" ) );
00370         }
00371 
00372         if ( oldincidence ) {
00373           // First we need to determine if the old and new incidences differ in
00374           // the attendee list only. If that's the case, then we need to get the
00375           // list of new attendees and the list of removed attendees and deal
00376           // with those lists separately.
00377 
00378           Attendee::List oldattendees = oldincidence->attendees();
00379           Attendee::List::ConstIterator ot;
00380 
00381           Attendee::List newAtts;  // newly added attendees
00382           Attendee::List remAtts;  // newly removed attendees
00383           sameAtts.clear();
00384 
00385           // make a list of newly added attendees and attendees in both old and new incidence.
00386           for ( it = attendees.begin(); it != attendees.end(); ++it ) {
00387             bool found = false;
00388             for ( ot = oldattendees.begin(); ot != oldattendees.end(); ++ot ) {
00389               if ( (*it)->email() == (*ot)->email() ) {
00390                 found = true;
00391                 break;
00392               }
00393             }
00394             if ( !found ) {
00395               newAtts << *it;
00396             } else {
00397               if ( (*it)->email() != incidence->organizer().email() ) { //skip organizer
00398                 sameAtts << *it;
00399               }
00400             }
00401           }
00402 
00403           // make a list of newly removed attendees
00404           for ( ot = oldattendees.begin(); ot != oldattendees.end(); ++ot ) {
00405             bool found = false;
00406             for ( it = attendees.begin(); it != attendees.end(); ++it ) {
00407               if ( (*it)->email() == (*ot)->email() ) {
00408                 found = true;
00409                 break;
00410               }
00411             }
00412             if ( !found ) {
00413               remAtts << *ot;
00414             }
00415           }
00416 
00417           // let's see if any else changed from the old incidence
00418           if ( compareIncsExceptAttendees( incidence, oldincidence ) ) {
00419             // no change, so no need to send an update to the original attendees list.
00420             sendUpdate = false;
00421           }
00422 
00423           // For new attendees, send them the new incidence as a new invitation.
00424           if ( newAtts.count() > 0 ) {
00425             const QStringList rList = recipients( newAtts );
00426             int newMail = KMessageBox::questionYesNoList(
00427               parent,
00428               i18n( "You are adding new attendees to the invitation \"%1\".\n"
00429                     "Do you want to email an invitation to these new attendees?" ).
00430               arg( incidence->summary() ),
00431               rList,
00432               i18n( "New Attendees" ),
00433               KGuiItem( i18n( "Send Email" ) ), KGuiItem( i18n( "Do Not Send" ) ) );
00434             if ( newMail == KMessageBox::Yes ) {
00435               KCal::MailScheduler scheduler( mCalendar );
00436               incidence->setRevision( 0 );
00437               scheduler.performTransaction( incidence, Scheduler::Request, rList.join( "," ) );
00438             }
00439           }
00440 
00441           // For removed attendees, tell them they are toast and send them a cancel.
00442           if ( remAtts.count() > 0 ) {
00443             const QStringList rList = recipients( remAtts );
00444             int newMail = KMessageBox::questionYesNoList(
00445               parent,
00446               i18n( "You removed attendees from the invitation \"%1\".\n"
00447                     "Do you want to email a cancellation message to these attendees?" ).
00448               arg( incidence->summary() ),
00449               rList,
00450               i18n( "Removed Attendees" ),
00451               KGuiItem( i18n( "Send Email" ) ), KGuiItem( i18n( "Do Not Send" ) ) );
00452             if ( newMail == KMessageBox::Yes ) {
00453               KCal::MailScheduler scheduler( mCalendar );
00454               scheduler.performTransaction( incidence, Scheduler::Cancel, rList.join( "," ) );
00455             }
00456           }
00457         }
00458 
00459         // For existing attendees, skip the update if there are no other changes except attendees
00460         if ( sameAtts.count() > 0 ) {
00461           const QStringList rList = recipients( sameAtts );
00462           int newMail;
00463           if ( sendUpdate ) {
00464             newMail = KMessageBox::questionYesNoList(
00465               parent,
00466               i18n( "You changed the invitation \"%1\".\n"
00467                     "Do you want to email an updated invitation to these attendees?" ).
00468               arg( incidence->summary() ),
00469               rList,
00470               i18n( "Send Invitation Update" ),
00471               KGuiItem( i18n( "Send Email" ) ), KGuiItem( i18n( "Do Not Send" ) ) );
00472           } else {
00473             newMail = KMessageBox::questionYesNoList(
00474               parent,
00475               i18n( "You changed the invitation attendee list only.\n"
00476                     "Do you want to email an updated invitation showing the new attendees?" ),
00477               rList,
00478               i18n( "Send Invitation Update" ),
00479               KGuiItem( i18n( "Send Email" ) ), KGuiItem( i18n( "Do Not Send" ) ) );
00480           }
00481           if ( newMail == KMessageBox::Yes ) {
00482             KCal::MailScheduler scheduler( mCalendar );
00483             incidence->setRevision( incidence->revision() + 1 );
00484             scheduler.performTransaction( incidence, Scheduler::Request, rList.join( "," ) );
00485           }
00486         }
00487         return true;
00488       }
00489 
00490       case KOGlobals::INCIDENCEDELETED:
00491         Q_ASSERT( incidence->type() == "Event" || incidence->type() == "Todo" );
00492         if ( incidence->type() == "Event" ) {
00493           txt = i18n( "You removed the invitation \"%1\".\n"
00494                       "Do you want to email the attendees that the event is canceled?" ).
00495                 arg( incidence->summary() );
00496         } else if ( incidence->type() == "Todo" ) {
00497           txt = i18n( "You removed the invitation \"%1\".\n"
00498                       "Do you want to email the attendees that the todo is canceled?" ).
00499                 arg( incidence->summary() );
00500         }
00501         break;
00502 
00503       case KOGlobals::INCIDENCEADDED:
00504         if ( incidence->type() == "Event" ) {
00505           txt = i18n( "The event \"%1\" includes other people.\n"
00506                       "Do you want to email the invitation to the attendees?" ).
00507                 arg( incidence->summary() );
00508         } else if ( incidence->type() == "Todo" ) {
00509           txt = i18n( "The todo \"%1\" includes other people.\n"
00510                       "Do you want to email the invitation to the attendees?" ).
00511                 arg( incidence->summary() );
00512         } else {
00513           txt = i18n( "This incidence includes other people. "
00514                       "Should an email be sent to the attendees?" );
00515         }
00516         break;
00517 
00518       default:
00519         kdError() << "Unsupported HowChanged action" << int( action ) << endl;
00520         break;
00521       }
00522 
00523       if ( useLastDialogAnswer ) {
00524         rc = lastUsedDialogAnswer;
00525       } else {
00526         lastUsedDialogAnswer = rc = KMessageBox::questionYesNo(
00527           parent, txt, i18n( "Group Scheduling Email" ),
00528           KGuiItem( i18n( "Send Email" ) ), KGuiItem( i18n( "Do Not Send" ) ) );
00529       }
00530     } else {
00531       return true;
00532     }
00533   } else if( incidence->type() == "Todo" ) {
00534     QString txt;
00535     Todo *todo = static_cast<Todo *>( incidence );
00536     Todo *oldtodo = static_cast<Todo *>( oldincidence );
00537     if ( todo && oldtodo &&
00538          todo->percentComplete() != oldtodo->percentComplete() &&
00539          method == Scheduler::Request ) {
00540       txt = i18n( "Your completion status in this task has been changed. "
00541                   "Do you want to send a status update to the task organizer?" );
00542       method = Scheduler::Reply;
00543       if ( useLastDialogAnswer ) {
00544         rc = lastUsedDialogAnswer;
00545       } else {
00546         lastUsedDialogAnswer = rc = KMessageBox::questionYesNo(
00547           parent, txt, i18n( "Group Scheduling Email" ),
00548           KGuiItem( i18n( "Send Update" ) ), KGuiItem( i18n( "Do Not Send" ) ) );
00549       }
00550     } else if ( attendeeStatusChanged && method == Scheduler::Request ) {
00551       txt = i18n( "Your status as a participant in this task changed. "
00552                   "Do you want to send a status update to the task organizer?" );
00553       method = Scheduler::Reply;
00554       if ( useLastDialogAnswer ) {
00555         rc = lastUsedDialogAnswer;
00556       } else {
00557         lastUsedDialogAnswer = rc = KMessageBox::questionYesNo(
00558           parent, txt, i18n( "Group Scheduling Email" ),
00559           KGuiItem( i18n( "Send Update" ) ), KGuiItem( i18n( "Do Not Send" ) ) );
00560       }
00561     } else {
00562       if ( action == KOGlobals::INCIDENCEDELETED ) {
00563         const QStringList myEmails = KOPrefs::instance()->allEmails();
00564         bool askConfirmation = false;
00565         for ( QStringList::ConstIterator it = myEmails.begin(); it != myEmails.end(); ++it ) {
00566           QString email = *it;
00567           Attendee *me = incidence->attendeeByMail(email);
00568           if ( me &&
00569                ( me->status() == KCal::Attendee::Accepted ||
00570                  me->status() == KCal::Attendee::Delegated ) ) {
00571             askConfirmation = true;
00572             break;
00573           }
00574         }
00575 
00576         if ( !askConfirmation ) {
00577           return true;
00578         }
00579 
00580         txt = i18n( "You had previously accepted your participation in this task. "
00581                     "Do you want to send an updated response to the organizer "
00582                     "removing yourself from the task?" );
00583         if ( useLastDialogAnswer ) {
00584           rc = lastUsedDialogAnswer;
00585         } else {
00586           lastUsedDialogAnswer = rc = KMessageBox::questionYesNo(
00587             parent, txt, i18n( "Group Scheduling Email" ),
00588             KGuiItem( i18n( "Send Update" ) ), KGuiItem( i18n( "Do Not Send" ) ) );
00589           setDoNotNotify( rc == KMessageBox::No );
00590         }
00591       } else {
00592         if ( useLastDialogAnswer ) {
00593           rc = lastUsedDialogAnswer;
00594         } else {
00595           if ( CalHelper::incOrganizerOwnsCalendar( mCalendar, incidence ) ) {
00596             txt = i18n( "<qt>"
00597                         "You are modifying the organizer's task. "
00598                         "Do you really want to edit it?<p>"
00599                         "If \"yes\", all the attendees will be emailed the updated invitation."
00600                         "</qt>" );
00601             lastUsedDialogAnswer = rc = KMessageBox::warningYesNo( parent, txt );
00602             if ( rc == KMessageBox::Yes ) {
00603               KCal::MailScheduler scheduler( mCalendar );
00604               scheduler.performTransaction( incidence, Scheduler::Request,
00605                                             recipients( incidence->attendees() ).join( "," ) );
00606             }
00607           } else {
00608             txt = i18n( "<qt>"
00609                         "You are not the organizer of this task. Editing it will "
00610                         "bring your invitation out of sync with the organizer's invitation. "
00611                         "Do you really want to edit it?<p>"
00612                         "If \"yes\", your local copy of the invitation will be different than "
00613                         "the organizer and any other task participants."
00614                         "</qt>" );
00615             lastUsedDialogAnswer = rc = KMessageBox::warningYesNo( parent, txt );
00616           }
00617         }
00618         return ( rc == KMessageBox::Yes );
00619       }
00620     }
00621   } else if ( incidence->type() == "Event" ) {
00622     QString txt;
00623     if ( attendeeStatusChanged && method == Scheduler::Request ) {
00624       txt = i18n( "Your status as an attendee of this event changed. "
00625                   "Do you want to send a status update to the event organizer?" );
00626       method = Scheduler::Reply;
00627       if ( useLastDialogAnswer ) {
00628         rc = lastUsedDialogAnswer;
00629       } else {
00630         lastUsedDialogAnswer = rc = KMessageBox::questionYesNo(
00631           parent, txt, i18n( "Group Scheduling Email" ),
00632           KGuiItem( i18n( "Send Update" ) ), KGuiItem( i18n( "Do Not Send" ) ) );
00633       }
00634     } else {
00635       if ( action == KOGlobals::INCIDENCEDELETED ) {
00636         const QStringList myEmails = KOPrefs::instance()->allEmails();
00637         bool askConfirmation = false;
00638         for ( QStringList::ConstIterator it = myEmails.begin(); it != myEmails.end(); ++it ) {
00639           QString email = *it;
00640           Attendee *me = incidence->attendeeByMail(email);
00641           if ( me &&
00642                ( me->status() == KCal::Attendee::Accepted ||
00643                  me->status() == KCal::Attendee::Delegated ) ) {
00644             askConfirmation = true;
00645             break;
00646           }
00647         }
00648 
00649         if ( !askConfirmation ) {
00650           return true;
00651         }
00652 
00653         txt = i18n( "You had previously accepted an invitation to this event. "
00654                     "Do you want to send an updated response to the organizer "
00655                     "declining the invitation?" );
00656         if ( useLastDialogAnswer ) {
00657           rc = lastUsedDialogAnswer;
00658         } else {
00659           lastUsedDialogAnswer = rc = KMessageBox::questionYesNo(
00660             parent, txt, i18n( "Group Scheduling Email" ),
00661             KGuiItem( i18n( "Send Update" ) ), KGuiItem( i18n( "Do Not Send" ) ) );
00662           setDoNotNotify( rc == KMessageBox::No );
00663         }
00664       } else {
00665         if ( useLastDialogAnswer ) {
00666           rc = lastUsedDialogAnswer;
00667         } else {
00668           if ( CalHelper::incOrganizerOwnsCalendar( mCalendar, incidence ) ) {
00669             txt = i18n( "<qt>"
00670                         "You are modifying the organizer's event. "
00671                         "Do you really want to edit it?<p>"
00672                         "If \"yes\", all the attendees will be emailed the updated invitation."
00673                         "</qt>" );
00674             lastUsedDialogAnswer = rc = KMessageBox::warningYesNo( parent, txt );
00675             if ( rc == KMessageBox::Yes ) {
00676               KCal::MailScheduler scheduler( mCalendar );
00677               scheduler.performTransaction( incidence, Scheduler::Request,
00678                                             recipients( incidence->attendees() ).join( "," ) );
00679             }
00680           } else {
00681             txt = i18n( "<qt>"
00682                         "You are not the organizer of this event. Editing it will "
00683                         "bring your invitation out of sync with the organizer's invitation. "
00684                         "Do you really want to edit it?<p>"
00685                         "If \"yes\", your local copy of the invitation will be different than "
00686                         "the organizer and any other event participants."
00687                         "</qt>" );
00688             lastUsedDialogAnswer = rc = KMessageBox::warningYesNo( parent, txt );
00689           }
00690         }
00691         return ( rc == KMessageBox::Yes );
00692       }
00693     }
00694   } else {
00695     kdWarning(5850) << "Groupware messages for Journals are not implemented yet!" << endl;
00696     return true;
00697   }
00698 
00699   if ( rc == KMessageBox::Yes ) {
00700     // We will be sending out a message here. Now make sure there is
00701     // some summary
00702     if( incidence->summary().isEmpty() )
00703       incidence->setSummary( i18n("<No summary given>") );
00704 
00705     // Send the mail
00706     KCal::MailScheduler scheduler( mCalendar );
00707     scheduler.performTransaction( incidence, method );
00708 
00709     return true;
00710   } else if ( rc == KMessageBox::No ) {
00711     return true;
00712   } else {
00713     return false;
00714   }
00715 }
00716 
00717 void KOGroupware::sendCounterProposal(KCal::Calendar *calendar, KCal::Event * oldEvent, KCal::Event * newEvent) const
00718 {
00719   if ( !oldEvent || !newEvent || *oldEvent == *newEvent || !KOPrefs::instance()->mUseGroupwareCommunication )
00720     return;
00721   if ( KOPrefs::instance()->outlookCompatCounterProposals() ) {
00722     Incidence* tmp = oldEvent->clone();
00723     tmp->setSummary( i18n("Counter proposal: %1").arg( newEvent->summary() ) );
00724     tmp->setDescription( newEvent->description() );
00725     tmp->addComment( i18n("Proposed new meeting time: %1 - %2").
00726                      arg( IncidenceFormatter::dateToString( newEvent->dtStart() ),
00727                           IncidenceFormatter::dateToString( newEvent->dtEnd() ) ) );
00728     KCal::MailScheduler scheduler( calendar );
00729     scheduler.performTransaction( tmp, Scheduler::Reply );
00730     delete tmp;
00731   } else {
00732     KCal::MailScheduler scheduler( calendar );
00733     scheduler.performTransaction( newEvent, Scheduler::Counter );
00734   }
00735 }
00736 
00737 #include "kogroupware.moc"
KDE Home | KDE Accessibility Home | Description of Access Keys