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 <libemailfunctions/email.h>
00043 #include <libkcal/attendee.h>
00044 #include <libkcal/journal.h>
00045 #include <libkcal/incidenceformatter.h>
00046 #include <kdebug.h>
00047 #include <kmessagebox.h>
00048 #include <kstandarddirs.h>
00049 #include <kdirwatch.h>
00050 #include <qfile.h>
00051 #include <qregexp.h>
00052 #include <qdir.h>
00053 
00054 FreeBusyManager *KOGroupware::mFreeBusyManager = 0;
00055 
00056 KOGroupware *KOGroupware::mInstance = 0;
00057 
00058 KOGroupware *KOGroupware::create( CalendarView *view,
00059                                   KCal::CalendarResources *calendar )
00060 {
00061   if( !mInstance )
00062     mInstance = new KOGroupware( view, calendar );
00063   return mInstance;
00064 }
00065 
00066 KOGroupware *KOGroupware::instance()
00067 {
00068   // Doesn't create, that is the task of create()
00069   Q_ASSERT( mInstance );
00070   return mInstance;
00071 }
00072 
00073 
00074  KOGroupware::KOGroupware( CalendarView* view, KCal::CalendarResources* cal )
00075    : QObject( 0, "kmgroupware_instance" ), mView( view ), mCalendar( cal )
00076 {
00077   // Set up the dir watch of the three incoming dirs
00078   KDirWatch* watcher = KDirWatch::self();
00079   watcher->addDir( locateLocal( "data", "korganizer/income.accepted/" ) );
00080   watcher->addDir( locateLocal( "data", "korganizer/income.tentative/" ) );
00081   watcher->addDir( locateLocal( "data", "korganizer/income.cancel/" ) );
00082   watcher->addDir( locateLocal( "data", "korganizer/income.reply/" ) );
00083   connect( watcher, SIGNAL( dirty( const QString& ) ),
00084            this, SLOT( incomingDirChanged( const QString& ) ) );
00085   // Now set the ball rolling
00086   incomingDirChanged( locateLocal( "data", "korganizer/income.accepted/" ) );
00087   incomingDirChanged( locateLocal( "data", "korganizer/income.tentative/" ) );
00088   incomingDirChanged( locateLocal( "data", "korganizer/income.cancel/" ) );
00089   incomingDirChanged( locateLocal( "data", "korganizer/income.reply/" ) );
00090 }
00091 
00092 FreeBusyManager *KOGroupware::freeBusyManager()
00093 {
00094   if ( !mFreeBusyManager ) {
00095     mFreeBusyManager = new FreeBusyManager( this, "freebusymanager" );
00096     mFreeBusyManager->setCalendar( mCalendar );
00097     connect( mCalendar, SIGNAL( calendarChanged() ),
00098              mFreeBusyManager, SLOT( slotPerhapsUploadFB() ) );
00099   }
00100 
00101   return mFreeBusyManager;
00102 }
00103 
00104 void KOGroupware::incomingDirChanged( const QString& path )
00105 {
00106   const QString incomingDirName = locateLocal( "data","korganizer/" )
00107                                   + "income.";
00108   if ( !path.startsWith( incomingDirName ) ) {
00109     kdDebug(5850) << "incomingDirChanged: Wrong dir " << path << endl;
00110     return;
00111   }
00112   QString action = path.mid( incomingDirName.length() );
00113   while ( action.length() > 0 && action[ action.length()-1 ] == '/' )
00114     // Strip slashes at the end
00115     action.truncate( action.length()-1 );
00116 
00117   // Handle accepted invitations
00118   QDir dir( path );
00119   const QStringList files = dir.entryList( QDir::Files );
00120   if ( files.isEmpty() )
00121     // No more files here
00122     return;
00123 
00124   // Read the file and remove it
00125   QFile f( path + "/" + files[0] );
00126   if (!f.open(IO_ReadOnly)) {
00127     kdError(5850) << "Can't open file '" << files[0] << "'" << endl;
00128     return;
00129   }
00130   QTextStream t(&f);
00131   t.setEncoding( QTextStream::UnicodeUTF8 );
00132   QString receiver = KPIM::getFirstEmailAddress( t.readLine() );
00133   QString iCal = t.read();
00134 
00135   f.remove();
00136 
00137   ScheduleMessage *message = mFormat.parseScheduleMessage( mCalendar, iCal );
00138   if ( !message ) {
00139     QString errorMessage;
00140     if (mFormat.exception())
00141       errorMessage = i18n( "Error message: %1" ).arg( mFormat.exception()->message() );
00142     kdDebug(5850) << "MailScheduler::retrieveTransactions() Error parsing "
00143                   << errorMessage << endl;
00144     KMessageBox::detailedError( mView,
00145         i18n("Error while processing an invitation or update."),
00146         errorMessage );
00147     return;
00148   }
00149 
00150   KCal::Scheduler::Method method =
00151     static_cast<KCal::Scheduler::Method>( message->method() );
00152   KCal::ScheduleMessage::Status status = message->status();
00153   KCal::Incidence* incidence =
00154     dynamic_cast<KCal::Incidence*>( message->event() );
00155   KCal::MailScheduler scheduler( mCalendar );
00156   if ( action.startsWith( "accepted" ) || action.startsWith( "tentative" ) ) {
00157     // Find myself and set my status. This can't be done in the scheduler,
00158     // since this does not know the choice I made in the KMail bpf
00159     KCal::Attendee::List attendees = incidence->attendees();
00160     KCal::Attendee::List::ConstIterator it;
00161     for ( it = attendees.begin(); it != attendees.end(); ++it ) {
00162       if( (*it)->email() == receiver ) {
00163         if ( action.startsWith( "accepted" ) )
00164           (*it)->setStatus( KCal::Attendee::Accepted );
00165         else
00166           (*it)->setStatus( KCal::Attendee::Tentative );
00167         break;
00168       }
00169     }
00170     scheduler.acceptTransaction( incidence, method, status );
00171   } else if ( action.startsWith( "cancel" ) )
00172     // Delete the old incidence, if one is present
00173     scheduler.acceptTransaction( incidence, KCal::Scheduler::Cancel, status );
00174   else if ( action.startsWith( "reply" ) )
00175     scheduler.acceptTransaction( incidence, method, status );
00176   else
00177     kdError(5850) << "Unknown incoming action " << action << endl;
00178   mView->updateView();
00179 }
00180 
00181 class KOInvitationFormatterHelper : public InvitationFormatterHelper
00182 {
00183   public:
00184     virtual QString generateLinkURL( const QString &id ) { return "kmail:groupware_request_" + id; }
00185 };
00186 
00187 /* This function sends mails if necessary, and makes sure the user really
00188  * want to change his calendar.
00189  *
00190  * Return true means accept the changes
00191  * Return false means revert the changes
00192  */
00193 bool KOGroupware::sendICalMessage( QWidget* parent,
00194                                    KCal::Scheduler::Method method,
00195                                    Incidence* incidence, bool isDeleting,
00196                                    bool statusChanged )
00197 {
00198   // If there are no attendees, don't bother
00199   if( incidence->attendees().isEmpty() )
00200     return true;
00201 
00202   bool isOrganizer = KOPrefs::instance()->thatIsMe( incidence->organizer().email() );
00203   int rc = 0;
00204   /*
00205    * There are two scenarios:
00206    * o "we" are the organizer, where "we" means any of the identities or mail
00207    *   addresses known to Kontact/PIM. If there are attendees, we need to mail
00208    *   them all, even if one or more of them are also "us". Otherwise there
00209    *   would be no way to invite a resource or our boss, other identities we
00210    *   also manage.
00211    * o "we: are not the organizer, which means we changed the completion status
00212    *   of a todo, or we changed our attendee status from, say, tentative to
00213    *   accepted. In both cases we only mail the organizer. All other changes
00214    *   bring us out of sync with the organizer, so we won't mail, if the user
00215    *   insists on applying them.
00216    */
00217 
00218   if ( isOrganizer ) {
00219     /* We are the organizer. If there is more than one attendee, or if there is
00220      * only one, and it's not the same as the organizer, ask the user to send
00221      * mail. */
00222     if ( incidence->attendees().count() > 1
00223         || incidence->attendees().first()->email() != incidence->organizer().email() ) {
00224       QString type;
00225       if( incidence->type() == "Event") type = i18n("event");
00226       else if( incidence->type() == "Todo" ) type = i18n("task");
00227       else if( incidence->type() == "Journal" ) type = i18n("journal entry");
00228       else type = incidence->type();
00229       QString txt = i18n( "This %1 includes other people. "
00230           "Should email be sent out to the attendees?" )
00231         .arg( type );
00232       rc = KMessageBox::questionYesNoCancel( parent, txt,
00233           i18n("Group Scheduling Email"), i18n("Send Email"), i18n("Do Not Send") );
00234     } else {
00235       return true;
00236     }
00237   } else if( incidence->type() == "Todo" ) {
00238     if( method == Scheduler::Request )
00239       // This is an update to be sent to the organizer
00240       method = Scheduler::Reply;
00241 
00242     // Ask if the user wants to tell the organizer about the current status
00243     QString txt = i18n( "Do you want to send a status update to the "
00244                         "organizer of this task?");
00245     rc = KMessageBox::questionYesNo( parent, txt, QString::null, i18n("Send Update"), i18n("Do Not Send") );
00246   } else if( incidence->type() == "Event" ) {
00247     QString txt;
00248     if ( statusChanged && method == Scheduler::Request ) {
00249       txt = i18n( "Your status as an attendee of this event "
00250           "changed. Do you want to send a status update to the "
00251           "organizer of this event?" );
00252       method = Scheduler::Reply;
00253       rc = KMessageBox::questionYesNo( parent, txt, QString::null, i18n("Send Update"), i18n("Do Not Send") );
00254     } else {
00255       if( isDeleting )
00256         txt = i18n( "You are not the organizer of this event. "
00257             "Deleting it will bring your calendar out of sync "
00258             "with the organizers calendar. Do you really want "
00259             "to delete it?" );
00260       else
00261         txt = i18n( "You are not the organizer of this event. "
00262             "Editing it will bring your calendar out of sync "
00263             "with the organizers calendar. Do you really want "
00264             "to edit it?" );
00265       rc = KMessageBox::warningYesNo( parent, txt );
00266       return ( rc == KMessageBox::Yes );
00267     }
00268   } else {
00269     kdWarning(5850) << "Groupware messages for Journals are not implemented yet!" << endl;
00270     return true;
00271   }
00272 
00273   if( rc == KMessageBox::Yes ) {
00274     // We will be sending out a message here. Now make sure there is
00275     // some summary
00276     if( incidence->summary().isEmpty() )
00277       incidence->setSummary( i18n("<No summary given>") );
00278 
00279     // Send the mail
00280     KCal::MailScheduler scheduler( mCalendar );
00281     scheduler.performTransaction( incidence, method );
00282 
00283     return true;
00284   } else if( rc == KMessageBox::No )
00285     return true;
00286   else
00287     return false;
00288 }
00289 
00290 
00291 #include "kogroupware.moc"
KDE Home | KDE Accessibility Home | Description of Access Keys