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