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