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() << "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   // PENDING(steffen): Is this safe?
00103   //job->deleteLater();
00104   delete this;
00105 }
00106 
00107 
00108 FreeBusyManager::FreeBusyManager( QObject *parent, const char *name )
00109   : QObject( parent, name ),
00110     mCalendar( 0 ), mTimerID( 0 ), mUploadingFreeBusy( false )
00111 {
00112 }
00113 
00114 void FreeBusyManager::setCalendar( KCal::Calendar *c )
00115 {
00116   mCalendar = c;
00117   if ( mCalendar ) {
00118     mFormat.setTimeZone( mCalendar->timeZoneId(), true );
00119   }
00120 }
00121 
00122 KCal::FreeBusy *FreeBusyManager::ownerFreeBusy()
00123 {
00124   QDateTime start = QDateTime::currentDateTime();
00125   QDateTime end = start.addDays( KOPrefs::instance()->mFreeBusyPublishDays );
00126 
00127   FreeBusy *freebusy = new FreeBusy( mCalendar, start, end );
00128   freebusy->setOrganizer( Person( KOPrefs::instance()->fullName(), 
00129                           KOPrefs::instance()->email() ) );
00130 
00131   return freebusy;
00132 }
00133 
00134 QString FreeBusyManager::ownerFreeBusyAsString()
00135 {
00136   FreeBusy *freebusy = ownerFreeBusy();
00137 
00138   QString result = freeBusyToIcal( freebusy );
00139 
00140   delete freebusy;
00141 
00142   return result;
00143 }
00144 
00145 QString FreeBusyManager::freeBusyToIcal( KCal::FreeBusy *freebusy )
00146 {
00147   return mFormat.createScheduleMessage( freebusy, Scheduler::Publish );
00148 }
00149 
00150 void FreeBusyManager::slotPerhapsUploadFB()
00151 {
00152   // user has automtic uploading disabled, bail out
00153   if ( !KOPrefs::instance()->freeBusyPublishAuto() )
00154      return;
00155   if( mTimerID != 0 )
00156     // A timer is already running, so we don't need to do anything
00157     return;
00158 
00159   int now = static_cast<int>( QDateTime::currentDateTime().toTime_t() );
00160   int eta = static_cast<int>( mNextUploadTime.toTime_t() ) - now;
00161 
00162   if( !mUploadingFreeBusy ) {
00163     // Not currently uploading
00164     if( mNextUploadTime.isNull() ||
00165     QDateTime::currentDateTime() > mNextUploadTime ) {
00166       // No uploading have been done in this session, or delay time is over
00167       publishFreeBusy();
00168       return;
00169     }
00170 
00171     // We're in the delay time and no timer is running. Start one
00172     if( eta <= 0 ) {
00173       // Sanity check failed - better do the upload
00174       publishFreeBusy();
00175       return;
00176     }
00177   } else {
00178     // We are currently uploading the FB list. Start the timer
00179     if( eta <= 0 ) {
00180       kdDebug(5850) << "This shouldn't happen! eta <= 0\n";
00181       eta = 10; // whatever
00182     }
00183   }
00184 
00185   // Start the timer
00186   mTimerID = startTimer( eta * 1000 );
00187 
00188   if( mTimerID == 0 )
00189     // startTimer failed - better do the upload
00190     publishFreeBusy();
00191 }
00192 
00193 // This is used for delayed Free/Busy list uploading
00194 void FreeBusyManager::timerEvent( QTimerEvent* )
00195 {
00196   publishFreeBusy();
00197 }
00198 
00203 void FreeBusyManager::publishFreeBusy()
00204 {
00205   // Already uploading? Skip this one then.
00206   if ( mUploadingFreeBusy )
00207     return;
00208   mUploadingFreeBusy = true;
00209 
00210   // If we have a timer running, it should be stopped now
00211   if( mTimerID != 0 ) {
00212     killTimer( mTimerID );
00213     mTimerID = 0;
00214   }
00215 
00216   // Save the time of the next free/busy uploading
00217   mNextUploadTime = QDateTime::currentDateTime();
00218   if( KOPrefs::instance()->mFreeBusyPublishDelay > 0 )
00219     mNextUploadTime = mNextUploadTime.addSecs(
00220         KOPrefs::instance()->mFreeBusyPublishDelay * 60 );
00221 
00222   QString messageText = ownerFreeBusyAsString();
00223 
00224   // We need to massage the list a bit so that Outlook understands
00225   // it.
00226   messageText = messageText.replace( QRegExp( "ORGANIZER\\s*:MAILTO:" ),
00227                                      "ORGANIZER:" );
00228 
00229   // Create a local temp file and save the message to it
00230   KTempFile tempFile;
00231   QTextStream *textStream = tempFile.textStream();
00232   if( textStream ) {
00233     *textStream << messageText;
00234     tempFile.close();
00235 
00236 #if 0
00237     QString defaultEmail = KOCore()::self()->email();
00238     QString emailHost = defaultEmail.mid( defaultEmail.find( '@' ) + 1 );
00239 
00240     // Put target string together
00241     KURL targetURL;
00242     if( KOPrefs::instance()->mPublishKolab ) {
00243       // we use Kolab
00244       QString server;
00245       if( KOPrefs::instance()->mPublishKolabServer == "%SERVER%" ||
00246       KOPrefs::instance()->mPublishKolabServer.isEmpty() )
00247     server = emailHost;
00248       else
00249     server = KOPrefs::instance()->mPublishKolabServer;
00250 
00251       targetURL.setProtocol( "webdavs" );
00252       targetURL.setHost( server );
00253 
00254       QString fbname = KOPrefs::instance()->mPublishUserName;
00255       int at = fbname.find('@');
00256       if( at > 1 && fbname.length() > (uint)at ) {
00257     fbname = fbname.left(at);
00258       }
00259       targetURL.setPath( "/freebusy/" + fbname + ".ifb" );
00260       targetURL.setUser( KOPrefs::instance()->mPublishUserName );
00261       targetURL.setPass( KOPrefs::instance()->mPublishPassword );
00262     } else {
00263       // we use something else
00264       targetURL = KOPrefs::instance()->mPublishAnyURL.replace( "%SERVER%",
00265                                                                emailHost );
00266       targetURL.setUser( KOPrefs::instance()->mPublishUserName );
00267       targetURL.setPass( KOPrefs::instance()->mPublishPassword );
00268     }
00269 #endif
00270 
00271     KURL targetURL ( KOPrefs::instance()->freeBusyPublishUrl() );
00272     targetURL.setUser( KOPrefs::instance()->mFreeBusyPublishUser );
00273     targetURL.setPass( KOPrefs::instance()->mFreeBusyPublishPassword );
00274 
00275     KURL src;
00276     src.setPath( tempFile.name() );
00277 
00278     kdDebug() << "FreeBusyManager::publishFreeBusy(): " << targetURL << endl;
00279 
00280     KIO::Job * job = KIO::file_copy( src, targetURL, -1,
00281                                      true /*overwrite*/,
00282                                      false /*don't resume*/,
00283                                      false /*don't show progress info*/ );
00284     connect( job, SIGNAL( result( KIO::Job * ) ),
00285              SLOT( slotUploadFreeBusyResult( KIO::Job * ) ) );
00286   }
00287 }
00288 
00289 void FreeBusyManager::slotUploadFreeBusyResult(KIO::Job *_job)
00290 {
00291     KIO::FileCopyJob* job = static_cast<KIO::FileCopyJob *>(_job);
00292     if ( job->error() )
00293         KMessageBox::sorry( 0,
00294           i18n( "<qt>The software could not upload your free/busy list to the "
00295                 "URL '%1'. There might be a problem with the access rights, or "
00296                 "you specified an incorrect URL. The system said: <em>%2</em>."
00297                 "<br>Please check the URL or contact your system administrator."
00298                 "</qt>" ).arg( job->destURL().prettyURL() )
00299                          .arg( job->errorString() ) );
00300     // Delete temp file
00301     KURL src = job->srcURL();
00302     Q_ASSERT( src.isLocalFile() );
00303     if( src.isLocalFile() )
00304         QFile::remove(src.path());
00305     mUploadingFreeBusy = false;
00306 }
00307 
00308 bool FreeBusyManager::retrieveFreeBusy( const QString &email )
00309 {
00310   kdDebug() << "FreeBusyManager::retrieveFreeBusy(): " << email << endl;
00311 
00312   if( KOPrefs::instance()->thatIsMe( email ) ) {
00313     // Don't download our own free-busy list from the net
00314     kdDebug() << "freebusy of owner" << endl;
00315     emit freeBusyRetrieved( ownerFreeBusy(), email );
00316     return true;
00317   }
00318 
00319   // Check for cached copy of free/busy list
00320   KCal::FreeBusy *fb = loadFreeBusy( email );
00321   if ( fb ) {
00322     emit freeBusyRetrieved( fb, email );
00323   }
00324 
00325   // Don't download free/busy if the user does not want it.
00326   if( !KOPrefs::instance()->mFreeBusyRetrieveAuto )
00327     return false;
00328 
00329   mRetrieveQueue.append( email );
00330 
00331   if ( mRetrieveQueue.count() > 1 ) return true;
00332 
00333   return processRetrieveQueue();
00334 }
00335 
00336 bool FreeBusyManager::processRetrieveQueue()
00337 {
00338   if ( mRetrieveQueue.isEmpty() ) return true;
00339 
00340   QString email = mRetrieveQueue.first();
00341   mRetrieveQueue.pop_front();
00342 
00343   KURL sourceURL = freeBusyUrl( email );
00344 
00345   kdDebug() << "FreeBusyManager::retrieveFreeBusy(): url: " << sourceURL.url()
00346             << endl;
00347 
00348   if ( !sourceURL.isValid() ) {
00349     kdDebug(5850) << "Invalid FB URL\n";
00350     return false;
00351   }
00352 
00353   FreeBusyDownloadJob *job = new FreeBusyDownloadJob( email, sourceURL, this,
00354                                                       "freebusy_download_job" );
00355   connect( job, SIGNAL( freeBusyDownloaded( KCal::FreeBusy *,
00356                                             const QString & ) ),
00357        SIGNAL( freeBusyRetrieved( KCal::FreeBusy *, const QString & ) ) );
00358   connect( job, SIGNAL( freeBusyDownloaded( KCal::FreeBusy *,
00359                                             const QString & ) ),
00360            SLOT( processRetrieveQueue() ) );
00361 
00362   return true;
00363 }
00364 
00365 void FreeBusyManager::cancelRetrieval()
00366 {
00367   mRetrieveQueue.clear();
00368 }
00369 
00370 KURL FreeBusyManager::freeBusyUrl( const QString &email )
00371 {
00372   // First check if there is a specific FB url for this email
00373   QString configFile = locateLocal( "data", "korganizer/freebusyurls" );
00374   KConfig cfg( configFile );
00375 
00376   cfg.setGroup( email );
00377   QString url = cfg.readEntry( "url" );
00378   if ( !url.isEmpty() ) {
00379     return KURL( url );
00380   }
00381 
00382   // None found. Check if we do automatic FB retrieving then
00383   if ( !KOPrefs::instance()->mFreeBusyRetrieveAuto )
00384     // No, so no FB list here
00385     return KURL();
00386 
00387   // Sanity check: Don't download if it's not a correct email
00388   // address (this also avoids downloading for "(empty email)").
00389   int emailpos = email.find( '@' );
00390   if( emailpos == -1 )
00391     return KURL();
00392 
00393   // Cut off everything left of the @ sign to get the user name.
00394   const QString emailName = email.left( emailpos );
00395   const QString emailHost = email.mid( emailpos + 1 );
00396 
00397   // Build the URL
00398   KURL sourceURL;
00399   sourceURL = KOPrefs::instance()->mFreeBusyRetrieveUrl;
00400 
00401   // Don't try to fetch free/busy data for users not on the specified servers
00402   // This tests if the hostnames match, or one is a subset of the other
00403   const QString hostDomain = sourceURL.host();
00404   if ( hostDomain != emailHost && !hostDomain.endsWith( '.' + emailHost )
00405        && !emailHost.endsWith( '.' + hostDomain ) )
00406     // Host names do not match
00407     return KURL();
00408 
00409   if ( KOPrefs::instance()->mFreeBusyFullDomainRetrieval )
00410     sourceURL.setFileName( email + ".ifb" );
00411   else
00412     sourceURL.setFileName( emailName + ".ifb" );
00413   sourceURL.setUser( KOPrefs::instance()->mFreeBusyRetrieveUser );
00414   sourceURL.setPass( KOPrefs::instance()->mFreeBusyRetrievePassword );
00415 
00416   return sourceURL;
00417 }
00418 
00419 KCal::FreeBusy *FreeBusyManager::iCalToFreeBusy( const QCString &data )
00420 {
00421   kdDebug() << "FreeBusyManager::iCalToFreeBusy()" << endl;
00422 
00423   QString freeBusyVCal = QString::fromUtf8( data );
00424   KCal::FreeBusy *fb = mFormat.parseFreeBusy( freeBusyVCal );
00425   if ( !fb ) {
00426     kdDebug() << "FreeBusyManager::iCalToFreeBusy(): Error parsing free/busy"
00427               << endl;
00428   } else {
00429     saveFreeBusy( fb, fb->organizer() );
00430   }
00431   return fb;
00432 }
00433 
00434 QString FreeBusyManager::freeBusyDir()
00435 {
00436   return locateLocal( "data", "korganizer/freebusy" );
00437 }
00438 
00439 FreeBusy *FreeBusyManager::loadFreeBusy( const QString &email )
00440 {
00441   kdDebug() << "FreeBusyManager::loadFreeBusy(): " << email << endl;
00442 
00443   QString fbd = freeBusyDir();
00444 
00445   QFile f( fbd + "/" + email + ".ifb" );
00446   if ( !f.exists() ) {
00447     kdDebug() << "FreeBusyManager::loadFreeBusy() " << f.name()
00448               << " doesn't exist." << endl;
00449     return 0;
00450   }
00451 
00452   if ( !f.open( IO_ReadOnly ) ) {
00453     kdDebug() << "FreeBusyManager::loadFreeBusy() Unable to open file "
00454               << f.name() << endl;
00455     return 0;
00456   }
00457 
00458   QTextStream ts( &f );
00459   QString str = ts.read();
00460 
00461   return iCalToFreeBusy( str.utf8() );
00462 }
00463 
00464 bool FreeBusyManager::saveFreeBusy( FreeBusy *freebusy, const Person &person )
00465 {
00466   kdDebug() << "FreeBusyManager::saveFreeBusy(): " << person.fullName() << endl;
00467 
00468   QString fbd = freeBusyDir();
00469 
00470   QDir freeBusyDirectory( fbd );
00471   if ( !freeBusyDirectory.exists() ) {
00472     kdDebug() << "Directory " << fbd << " does not exist!" << endl;
00473     kdDebug() << "Creating directory: " << fbd << endl;
00474 
00475     if( !freeBusyDirectory.mkdir( fbd, true ) ) {
00476       kdDebug() << "Could not create directory: " << fbd << endl;
00477       return false;
00478     }
00479   }
00480 
00481   QString filename( fbd );
00482   filename += "/";
00483   filename += person.email();
00484   filename += ".ifb";
00485   QFile f( filename );
00486 
00487   kdDebug() << "FreeBusyManager::saveFreeBusy(): filename: " << filename
00488             << endl;
00489 
00490   freebusy->clearAttendees();
00491   freebusy->setOrganizer( person );
00492 
00493   QString messageText = mFormat.createScheduleMessage( freebusy,
00494                                                        Scheduler::Publish );
00495 
00496   if ( !f.open( IO_ReadWrite ) ) {
00497     kdDebug() << "acceptFreeBusy: Can't open:" << filename << " for writing"
00498               << endl;
00499     return false;
00500   }
00501   QTextStream t( &f );
00502   t << messageText;
00503   f.close();
00504 
00505   return true;
00506 }
00507 
00508 #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 Mar 23 22:45:23 2005 by doxygen 1.3.9.1 written by Dimitri van Heesch, © 1997-2003