korganizer Library API Documentation

freebusymanager.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   Copyright (c) 2004 Cornelius Schumacher <schumacher@kde.org>
00010 
00011   This program is free software; you can redistribute it and/or modify
00012   it under the terms of the GNU General Public License as published by
00013   the Free Software Foundation; either version 2 of the License, or
00014   (at your option) any later version.
00015 
00016   This program is distributed in the hope that it will be useful,
00017   but WITHOUT ANY WARRANTY; without even the implied warranty of
00018   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
00019   GNU General Public License for more details.
00020 
00021   You should have received a copy of the GNU General Public License
00022   along with this program; if not, write to the Free Software
00023   Foundation, Inc., 59 Temple Place - Suite 330, Boston,
00024   MA  02111-1307, USA.
00025 
00026   In addition, as a special exception, the copyright holders give
00027   permission to link the code of this program with any edition of
00028   the Qt library by Trolltech AS, Norway (or with modified versions
00029   of Qt that use the same license as Qt), and distribute linked
00030   combinations including the two.  You must obey the GNU General
00031   Public License in all respects for all of the code used other than
00032   Qt.  If you modify this file, you may extend this exception to
00033   your version of the file, but you are not obligated to do so.  If
00034   you do not wish to do so, delete this exception statement from
00035   your version.
00036 */
00037 
00038 #include "freebusymanager.h"
00039 
00040 #include "koprefs.h"
00041 #include "mailscheduler.h"
00042 
00043 #include <libkcal/incidencebase.h>
00044 #include <libkcal/attendee.h>
00045 #include <libkcal/freebusy.h>
00046 #include <libkcal/journal.h>
00047 #include <libkcal/calendarlocal.h>
00048 #include <libkcal/icalformat.h>
00049 
00050 #include <kio/job.h>
00051 #include <kdebug.h>
00052 #include <kmessagebox.h>
00053 #include <ktempfile.h>
00054 #include <kio/netaccess.h>
00055 #include <kapplication.h>
00056 #include <kconfig.h>
00057 #include <klocale.h>
00058 #include <kstandarddirs.h>
00059 
00060 #include <qfile.h>
00061 #include <qbuffer.h>
00062 #include <qregexp.h>
00063 #include <qdir.h>
00064 
00065 using namespace KCal;
00066 
00067 FreeBusyDownloadJob::FreeBusyDownloadJob( const QString &email, const KURL &url,
00068                                           FreeBusyManager *manager,
00069                                           const char *name )
00070   : QObject( manager, name ), mManager( manager ), mEmail( email )
00071 {
00072   KIO::Job *job = KIO::get( url, false, false );
00073   connect( job, SIGNAL( result( KIO::Job * ) ),
00074            SLOT( slotResult( KIO::Job * ) ) );
00075   connect( job, SIGNAL( data( KIO::Job *, const QByteArray & ) ),
00076            SLOT( slotData( KIO::Job *, const QByteArray & ) ) );
00077 }
00078 
00079 FreeBusyDownloadJob::~FreeBusyDownloadJob()
00080 {
00081 }
00082 
00083 
00084 void FreeBusyDownloadJob::slotData( KIO::Job *, const QByteArray &data )
00085 {
00086   QByteArray tmp = data;
00087   tmp.resize( tmp.size() + 1 );
00088   tmp[tmp.size()-1] = 0;
00089   mFreeBusyData += tmp;
00090 }
00091 
00092 void FreeBusyDownloadJob::slotResult( KIO::Job *job )
00093 {
00094   kdDebug(5850) << "FreeBusyDownloadJob::slotResult() " << mEmail << endl;
00095 
00096   if( job->error() ) {
00097     kdDebug(5850) << "FreeBusyDownloadJob::slotResult() job error :-(" << endl;
00098   }
00099 
00100   FreeBusy *fb = mManager->iCalToFreeBusy( mFreeBusyData );
00101   emit freeBusyDownloaded( fb, mEmail );
00102   deleteLater();
00103 }
00104 
00105 
00106 FreeBusyManager::FreeBusyManager( QObject *parent, const char *name )
00107   : QObject( parent, name ),
00108     mCalendar( 0 ), mTimerID( 0 ), mUploadingFreeBusy( false )
00109 {
00110 }
00111 
00112 void FreeBusyManager::setCalendar( KCal::Calendar *c )
00113 {
00114   mCalendar = c;
00115   if ( mCalendar ) {
00116     mFormat.setTimeZone( mCalendar->timeZoneId(), true );
00117   }
00118 }
00119 
00120 KCal::FreeBusy *FreeBusyManager::ownerFreeBusy()
00121 {
00122   QDateTime start = QDateTime::currentDateTime();
00123   QDateTime end = start.addDays( KOPrefs::instance()->mFreeBusyPublishDays );
00124 
00125   FreeBusy *freebusy = new FreeBusy( mCalendar, start, end );
00126   freebusy->setOrganizer( Person( KOPrefs::instance()->fullName(),
00127                           KOPrefs::instance()->email() ) );
00128 
00129   return freebusy;
00130 }
00131 
00132 QString FreeBusyManager::ownerFreeBusyAsString()
00133 {
00134   FreeBusy *freebusy = ownerFreeBusy();
00135 
00136   QString result = freeBusyToIcal( freebusy );
00137 
00138   delete freebusy;
00139 
00140   return result;
00141 }
00142 
00143 QString FreeBusyManager::freeBusyToIcal( KCal::FreeBusy *freebusy )
00144 {
00145   return mFormat.createScheduleMessage( freebusy, Scheduler::Publish );
00146 }
00147 
00148 void FreeBusyManager::slotPerhapsUploadFB()
00149 {
00150   // user has automatic uploading disabled, bail out
00151   if ( !KOPrefs::instance()->freeBusyPublishAuto() )
00152      return;
00153   if( mTimerID != 0 )
00154     // A timer is already running, so we don't need to do anything
00155     return;
00156 
00157   int now = static_cast<int>( QDateTime::currentDateTime().toTime_t() );
00158   int eta = static_cast<int>( mNextUploadTime.toTime_t() ) - now;
00159 
00160   if( !mUploadingFreeBusy ) {
00161     // Not currently uploading
00162     if( mNextUploadTime.isNull() ||
00163     QDateTime::currentDateTime() > mNextUploadTime ) {
00164       // No uploading have been done in this session, or delay time is over
00165       publishFreeBusy();
00166       return;
00167     }
00168 
00169     // We're in the delay time and no timer is running. Start one
00170     if( eta <= 0 ) {
00171       // Sanity check failed - better do the upload
00172       publishFreeBusy();
00173       return;
00174     }
00175   } else {
00176     // We are currently uploading the FB list. Start the timer
00177     if( eta <= 0 ) {
00178       kdDebug(5850) << "This shouldn't happen! eta <= 0\n";
00179       eta = 10; // whatever
00180     }
00181   }
00182 
00183   // Start the timer
00184   mTimerID = startTimer( eta * 1000 );
00185 
00186   if( mTimerID == 0 )
00187     // startTimer failed - better do the upload
00188     publishFreeBusy();
00189 }
00190 
00191 // This is used for delayed Free/Busy list uploading
00192 void FreeBusyManager::timerEvent( QTimerEvent* )
00193 {
00194   publishFreeBusy();
00195 }
00196 
00201 void FreeBusyManager::publishFreeBusy()
00202 {
00203   // Already uploading? Skip this one then.
00204   if ( mUploadingFreeBusy )
00205     return;
00206   mUploadingFreeBusy = true;
00207 
00208   // If we have a timer running, it should be stopped now
00209   if( mTimerID != 0 ) {
00210     killTimer( mTimerID );
00211     mTimerID = 0;
00212   }
00213 
00214   // Save the time of the next free/busy uploading
00215   mNextUploadTime = QDateTime::currentDateTime();
00216   if( KOPrefs::instance()->mFreeBusyPublishDelay > 0 )
00217     mNextUploadTime = mNextUploadTime.addSecs(
00218         KOPrefs::instance()->mFreeBusyPublishDelay * 60 );
00219 
00220   QString messageText = ownerFreeBusyAsString();
00221 
00222   // We need to massage the list a bit so that Outlook understands
00223   // it.
00224   messageText = messageText.replace( QRegExp( "ORGANIZER\\s*:mailto:" ),
00225                                      "ORGANIZER:" );
00226 
00227   // Create a local temp file and save the message to it
00228   KTempFile tempFile;
00229   QTextStream *textStream = tempFile.textStream();
00230   if( textStream ) {
00231     *textStream << messageText;
00232     tempFile.close();
00233 
00234 #if 0
00235     QString defaultEmail = KOCore()::self()->email();
00236     QString emailHost = defaultEmail.mid( defaultEmail.find( '@' ) + 1 );
00237 
00238     // Put target string together
00239     KURL targetURL;
00240     if( KOPrefs::instance()->mPublishKolab ) {
00241       // we use Kolab
00242       QString server;
00243       if( KOPrefs::instance()->mPublishKolabServer == "%SERVER%" ||
00244       KOPrefs::instance()->mPublishKolabServer.isEmpty() )
00245     server = emailHost;
00246       else
00247     server = KOPrefs::instance()->mPublishKolabServer;
00248 
00249       targetURL.setProtocol( "webdavs" );
00250       targetURL.setHost( server );
00251 
00252       QString fbname = KOPrefs::instance()->mPublishUserName;
00253       int at = fbname.find('@');
00254       if( at > 1 && fbname.length() > (uint)at ) {
00255     fbname = fbname.left(at);
00256       }
00257       targetURL.setPath( "/freebusy/" + fbname + ".ifb" );
00258       targetURL.setUser( KOPrefs::instance()->mPublishUserName );
00259       targetURL.setPass( KOPrefs::instance()->mPublishPassword );
00260     } else {
00261       // we use something else
00262       targetURL = KOPrefs::instance()->mPublishAnyURL.replace( "%SERVER%",
00263                                                                emailHost );
00264       targetURL.setUser( KOPrefs::instance()->mPublishUserName );
00265       targetURL.setPass( KOPrefs::instance()->mPublishPassword );
00266     }
00267 #endif
00268 
00269     KURL targetURL ( KOPrefs::instance()->freeBusyPublishUrl() );
00270     targetURL.setUser( KOPrefs::instance()->mFreeBusyPublishUser );
00271     targetURL.setPass( KOPrefs::instance()->mFreeBusyPublishPassword );
00272 
00273     KURL src;
00274     src.setPath( tempFile.name() );
00275 
00276     kdDebug(5850) << "FreeBusyManager::publishFreeBusy(): " << targetURL << endl;
00277 
00278     KIO::Job * job = KIO::file_copy( src, targetURL, -1,
00279                                      true /*overwrite*/,
00280                                      false /*don't resume*/,
00281                                      false /*don't show progress info*/ );
00282     connect( job, SIGNAL( result( KIO::Job * ) ),
00283              SLOT( slotUploadFreeBusyResult( KIO::Job * ) ) );
00284   }
00285 }
00286 
00287 void FreeBusyManager::slotUploadFreeBusyResult(KIO::Job *_job)
00288 {
00289     KIO::FileCopyJob* job = static_cast<KIO::FileCopyJob *>(_job);
00290     if ( job->error() )
00291         KMessageBox::sorry( 0,
00292           i18n( "<qt>The software could not upload your free/busy list to the "
00293                 "URL '%1'. There might be a problem with the access rights, or "
00294                 "you specified an incorrect URL. The system said: <em>%2</em>."
00295                 "<br>Please check the URL or contact your system administrator."
00296                 "</qt>" ).arg( job->destURL().prettyURL() )
00297                          .arg( job->errorString() ) );
00298     // Delete temp file
00299     KURL src = job->srcURL();
00300     Q_ASSERT( src.isLocalFile() );
00301     if( src.isLocalFile() )
00302         QFile::remove(src.path());
00303     mUploadingFreeBusy = false;
00304 }
00305 
00306 bool FreeBusyManager::retrieveFreeBusy( const QString &email )
00307 {
00308   kdDebug(5850) << "FreeBusyManager::retrieveFreeBusy(): " << email << endl;
00309   if ( email.isEmpty() ) return false;
00310 
00311   if( KOPrefs::instance()->thatIsMe( email ) ) {
00312     // Don't download our own free-busy list from the net
00313     kdDebug(5850) << "freebusy of owner" << endl;
00314     emit freeBusyRetrieved( ownerFreeBusy(), email );
00315     return true;
00316   }
00317 
00318   // Check for cached copy of free/busy list
00319   KCal::FreeBusy *fb = loadFreeBusy( email );
00320   if ( fb ) {
00321     emit freeBusyRetrieved( fb, email );
00322   }
00323 
00324   // Don't download free/busy if the user does not want it.
00325   if( !KOPrefs::instance()->mFreeBusyRetrieveAuto )
00326     return false;
00327 
00328   mRetrieveQueue.append( email );
00329 
00330   if ( mRetrieveQueue.count() > 1 ) return true;
00331 
00332   return processRetrieveQueue();
00333 }
00334 
00335 bool FreeBusyManager::processRetrieveQueue()
00336 {
00337   if ( mRetrieveQueue.isEmpty() ) return true;
00338 
00339   QString email = mRetrieveQueue.first();
00340   mRetrieveQueue.pop_front();
00341 
00342   KURL sourceURL = freeBusyUrl( email );
00343 
00344   kdDebug(5850) << "FreeBusyManager::retrieveFreeBusy(): url: " << sourceURL
00345             << endl;
00346 
00347   if ( !sourceURL.isValid() ) {
00348     kdDebug(5850) << "Invalid FB URL\n";
00349     return false;
00350   }
00351 
00352   FreeBusyDownloadJob *job = new FreeBusyDownloadJob( email, sourceURL, this,
00353                                                       "freebusy_download_job" );
00354   connect( job, SIGNAL( freeBusyDownloaded( KCal::FreeBusy *,
00355                                             const QString & ) ),
00356        SIGNAL( freeBusyRetrieved( KCal::FreeBusy *, const QString & ) ) );
00357   connect( job, SIGNAL( freeBusyDownloaded( KCal::FreeBusy *,
00358                                             const QString & ) ),
00359            SLOT( processRetrieveQueue() ) );
00360 
00361   return true;
00362 }
00363 
00364 void FreeBusyManager::cancelRetrieval()
00365 {
00366   mRetrieveQueue.clear();
00367 }
00368 
00369 KURL FreeBusyManager::freeBusyUrl( const QString &email )
00370 {
00371   // First check if there is a specific FB url for this email
00372   QString configFile = locateLocal( "data", "korganizer/freebusyurls" );
00373   KConfig cfg( configFile );
00374 
00375   cfg.setGroup( email );
00376   QString url = cfg.readEntry( "url" );
00377   if ( !url.isEmpty() ) {
00378     return KURL( url );
00379   }
00380 
00381   // None found. Check if we do automatic FB retrieving then
00382   if ( !KOPrefs::instance()->mFreeBusyRetrieveAuto )
00383     // No, so no FB list here
00384     return KURL();
00385 
00386   // Sanity check: Don't download if it's not a correct email
00387   // address (this also avoids downloading for "(empty email)").
00388   int emailpos = email.find( '@' );
00389   if( emailpos == -1 )
00390     return KURL();
00391 
00392   // Cut off everything left of the @ sign to get the user name.
00393   const QString emailName = email.left( emailpos );
00394   const QString emailHost = email.mid( emailpos + 1 );
00395 
00396   // Build the URL
00397   KURL sourceURL;
00398   sourceURL = KOPrefs::instance()->mFreeBusyRetrieveUrl;
00399 
00400   // This test is disabled to make the multidomains of Kolab2 work.
00401   // It's a temporary workaround until a real solution can be agreed with
00402   // the kdepim people
00403 #if 0
00404   // Don't try to fetch free/busy data for users not on the specified servers
00405   // This tests if the hostnames match, or one is a subset of the other
00406   const QString hostDomain = sourceURL.host();
00407   if ( hostDomain != emailHost && !hostDomain.endsWith( '.' + emailHost )
00408        && !emailHost.endsWith( '.' + hostDomain ) )
00409     // Host names do not match
00410     return KURL();
00411 
00412   if ( KOPrefs::instance()->mFreeBusyFullDomainRetrieval )
00413     sourceURL.setFileName( email + ".ifb" );
00414   else
00415     sourceURL.setFileName( emailName + ".ifb" );
00416 #endif
00417 
00418   //Add some intelligence to the fb URL (MS Outlook style)
00419   QString fbAddress = sourceURL.fileName();
00420   fbAddress.replace( "%EMAIL%", email );
00421   fbAddress.replace( "%NAME%", emailName );
00422   fbAddress.replace( "%SERVER%", emailHost );
00423 
00424   //Just set it to what the user wants, make no assumptions on his/her behalf
00425   kdDebug() << "FreeBusyManager::freeBusyUrl(): " << sourceURL.fileName()
00426             << " set to " << fbAddress << "."
00427             << endl;
00428   sourceURL.setFileName(  fbAddress );
00429 
00430   sourceURL.setUser( KOPrefs::instance()->mFreeBusyRetrieveUser );
00431   sourceURL.setPass( KOPrefs::instance()->mFreeBusyRetrievePassword );
00432 
00433   return sourceURL;
00434 }
00435 
00436 KCal::FreeBusy *FreeBusyManager::iCalToFreeBusy( const QCString &data )
00437 {
00438   kdDebug(5850) << "FreeBusyManager::iCalToFreeBusy()" << endl;
00439 
00440   QString freeBusyVCal = QString::fromUtf8( data );
00441   KCal::FreeBusy *fb = mFormat.parseFreeBusy( freeBusyVCal );
00442   if ( !fb ) {
00443     kdDebug(5850) << "FreeBusyManager::iCalToFreeBusy(): Error parsing free/busy"
00444               << endl;
00445   } else {
00446     saveFreeBusy( fb, fb->organizer() );
00447   }
00448   return fb;
00449 }
00450 
00451 QString FreeBusyManager::freeBusyDir()
00452 {
00453   return locateLocal( "data", "korganizer/freebusy" );
00454 }
00455 
00456 FreeBusy *FreeBusyManager::loadFreeBusy( const QString &email )
00457 {
00458   kdDebug(5850) << "FreeBusyManager::loadFreeBusy(): " << email << endl;
00459 
00460   QString fbd = freeBusyDir();
00461 
00462   QFile f( fbd + "/" + email + ".ifb" );
00463   if ( !f.exists() ) {
00464     kdDebug(5850) << "FreeBusyManager::loadFreeBusy() " << f.name()
00465               << " doesn't exist." << endl;
00466     return 0;
00467   }
00468 
00469   if ( !f.open( IO_ReadOnly ) ) {
00470     kdDebug(5850) << "FreeBusyManager::loadFreeBusy() Unable to open file "
00471               << f.name() << endl;
00472     return 0;
00473   }
00474 
00475   QTextStream ts( &f );
00476   QString str = ts.read();
00477 
00478   return iCalToFreeBusy( str.utf8() );
00479 }
00480 
00481 bool FreeBusyManager::saveFreeBusy( FreeBusy *freebusy, const Person &person )
00482 {
00483   kdDebug(5850) << "FreeBusyManager::saveFreeBusy(): " << person.fullName() << endl;
00484 
00485   QString fbd = freeBusyDir();
00486 
00487   QDir freeBusyDirectory( fbd );
00488   if ( !freeBusyDirectory.exists() ) {
00489     kdDebug(5850) << "Directory " << fbd << " does not exist!" << endl;
00490     kdDebug(5850) << "Creating directory: " << fbd << endl;
00491 
00492     if( !freeBusyDirectory.mkdir( fbd, true ) ) {
00493       kdDebug(5850) << "Could not create directory: " << fbd << endl;
00494       return false;
00495     }
00496   }
00497 
00498   QString filename( fbd );
00499   filename += "/";
00500   filename += person.email();
00501   filename += ".ifb";
00502   QFile f( filename );
00503 
00504   kdDebug(5850) << "FreeBusyManager::saveFreeBusy(): filename: " << filename
00505             << endl;
00506 
00507   freebusy->clearAttendees();
00508   freebusy->setOrganizer( person );
00509 
00510   QString messageText = mFormat.createScheduleMessage( freebusy,
00511                                                        Scheduler::Publish );
00512 
00513   if ( !f.open( IO_ReadWrite ) ) {
00514     kdDebug(5850) << "acceptFreeBusy: Can't open:" << filename << " for writing"
00515               << endl;
00516     return false;
00517   }
00518   QTextStream t( &f );
00519   t << messageText;
00520   f.close();
00521 
00522   return true;
00523 }
00524 
00525 #include "freebusymanager.moc"
KDE Logo
This file is part of the documentation for korganizer Library Version 3.3.2.
Documentation copyright © 1996-2004 the KDE developers.
Generated on Wed Jul 25 11:20:58 2007 by doxygen 1.4.2 written by Dimitri van Heesch, © 1997-2003