• Skip to content
  • Skip to link menu
KDE 4.2 API Reference
  • KDE API Reference
  • kdepim
  • Sitemap
  • Contact Us
 

korganizer

freebusymanager.cpp

Go to the documentation of this file.
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�vdalens 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., 51 Franklin Street, Fifth Floor, Boston,
00024   MA  02110-1301, 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 #include "koprefs.h"
00040 #include "mailscheduler.h"
00041 
00042 #include <kabc/stdaddressbook.h>
00043 #include <kabc/addressee.h>
00044 
00045 #include <kcal/incidencebase.h>
00046 #include <kcal/attendee.h>
00047 #include <kcal/freebusy.h>
00048 #include <kcal/journal.h>
00049 #include <kcal/calendarlocal.h>
00050 #include <kcal/icalformat.h>
00051 
00052 #include <kio/job.h>
00053 #include <kio/netaccess.h>
00054 #include <kdebug.h>
00055 #include <kmessagebox.h>
00056 #include <ktemporaryfile.h>
00057 #include <kapplication.h>
00058 #include <kconfig.h>
00059 #include <klocale.h>
00060 #include <kstandarddirs.h>
00061 
00062 #include <QFile>
00063 #include <QBuffer>
00064 #include <QRegExp>
00065 #include <QDir>
00066 #include <QTimerEvent>
00067 #include <QTextStream>
00068 #include <QByteArray>
00069 
00070 using namespace KCal;
00071 
00072 FreeBusyDownloadJob::FreeBusyDownloadJob( const QString &email, const KUrl &url,
00073                                           FreeBusyManager *manager )
00074   : QObject( manager ), mManager( manager ), mEmail( email )
00075 {
00076   KIO::Job *job = KIO::get( url, KIO::NoReload, KIO::HideProgressInfo );
00077   connect( job, SIGNAL(result(KJob *)), SLOT(slotResult(KJob *)) );
00078   connect( job, SIGNAL(data(KIO::Job *,const QByteArray &)),
00079            SLOT(slotData(KIO::Job *,const QByteArray &)) );
00080 }
00081 
00082 FreeBusyDownloadJob::~FreeBusyDownloadJob()
00083 {
00084 }
00085 
00086 void FreeBusyDownloadJob::slotData( KIO::Job *, const QByteArray &data )
00087 {
00088   QByteArray tmp = data;
00089   tmp.resize( tmp.size() + 1 );
00090   tmp[tmp.size()-1] = 0;
00091   mFreeBusyData += tmp;
00092 }
00093 
00094 void FreeBusyDownloadJob::slotResult( KJob *job )
00095 {
00096   kDebug() << mEmail;
00097 
00098   if ( job->error() ) {
00099     kDebug() << "job error :-(";
00100   }
00101 
00102   FreeBusy *fb = mManager->iCalToFreeBusy( mFreeBusyData );
00103   if ( fb ) {
00104     Person p = fb->organizer();
00105     p.setEmail( mEmail );
00106     mManager->saveFreeBusy( fb, p );
00107   }
00108   emit freeBusyDownloaded( fb, mEmail );
00109   deleteLater();
00110 }
00111 
00113 
00114 FreeBusyManager::FreeBusyManager( QObject *parent ) :
00115   QObject( parent ),
00116   mCalendar( 0 ), mTimerID( 0 ), mUploadingFreeBusy( false ),
00117   mBrokenUrl( false )
00118 {
00119 }
00120 
00121 void FreeBusyManager::setCalendar( KCal::Calendar *c )
00122 {
00123   mCalendar = c;
00124   if ( mCalendar ) {
00125     mFormat.setTimeSpec( mCalendar->timeSpec() );
00126   }
00127 }
00128 
00129 KCal::FreeBusy *FreeBusyManager::ownerFreeBusy()
00130 {
00131   KDateTime start = KDateTime::currentUtcDateTime();
00132   KDateTime end = start.addDays( KOPrefs::instance()->mFreeBusyPublishDays );
00133 
00134   FreeBusy *freebusy = new FreeBusy( mCalendar, start, end );
00135   freebusy->setOrganizer( Person( KOPrefs::instance()->fullName(),
00136                                   KOPrefs::instance()->email() ) );
00137 
00138   return freebusy;
00139 }
00140 
00141 QString FreeBusyManager::ownerFreeBusyAsString()
00142 {
00143   FreeBusy *freebusy = ownerFreeBusy();
00144 
00145   QString result = freeBusyToIcal( freebusy );
00146 
00147   delete freebusy;
00148 
00149   return result;
00150 }
00151 
00152 QString FreeBusyManager::freeBusyToIcal( KCal::FreeBusy *freebusy )
00153 {
00154   return mFormat.createScheduleMessage( freebusy, iTIPPublish );
00155 }
00156 
00157 void FreeBusyManager::slotPerhapsUploadFB()
00158 {
00159   // user has automatic uploading disabled, bail out
00160   if ( !KOPrefs::instance()->freeBusyPublishAuto() ||
00161        KOPrefs::instance()->freeBusyPublishUrl().isEmpty() ) {
00162      return;
00163   }
00164 
00165   if( mTimerID != 0 ) {
00166     // A timer is already running, so we don't need to do anything
00167     return;
00168   }
00169 
00170   int now = static_cast<int>( QDateTime::currentDateTime().toTime_t() );
00171   int eta = static_cast<int>( mNextUploadTime.toTime_t() ) - now;
00172 
00173   if ( !mUploadingFreeBusy ) {
00174     // Not currently uploading
00175     if ( mNextUploadTime.isNull() ||
00176          QDateTime::currentDateTime() > mNextUploadTime ) {
00177       // No uploading have been done in this session, or delay time is over
00178       publishFreeBusy();
00179       return;
00180     }
00181 
00182     // We're in the delay time and no timer is running. Start one
00183     if ( eta <= 0 ) {
00184       // Sanity check failed - better do the upload
00185       publishFreeBusy();
00186       return;
00187     }
00188   } else {
00189     // We are currently uploading the FB list. Start the timer
00190     if ( eta <= 0 ) {
00191       kDebug() << "This shouldn't happen! eta <= 0";
00192       eta = 10; // whatever
00193     }
00194   }
00195 
00196   // Start the timer
00197   mTimerID = startTimer( eta * 1000 );
00198 
00199   if ( mTimerID == 0 ) {
00200     // startTimer failed - better do the upload
00201     publishFreeBusy();
00202   }
00203 }
00204 
00205 // This is used for delayed Free/Busy list uploading
00206 void FreeBusyManager::timerEvent( QTimerEvent * )
00207 {
00208   publishFreeBusy();
00209 }
00210 
00211 void FreeBusyManager::setBrokenUrl( bool isBroken )
00212 {
00213   mBrokenUrl = isBroken;
00214 }
00215 
00220 void FreeBusyManager::publishFreeBusy()
00221 {
00222   // Already uploading? Skip this one then.
00223   if ( mUploadingFreeBusy ) {
00224     return;
00225   }
00226   KUrl targetURL ( KOPrefs::instance()->freeBusyPublishUrl() );
00227   if ( targetURL.isEmpty() )  {
00228     KMessageBox::sorry(
00229       0,
00230       i18n( "<qt><p>No URL configured for uploading your free/busy list. "
00231             "Please set it in KOrganizer's configuration dialog, on the "
00232             "\"Free/Busy\" page.</p>"
00233             "<p>Contact your system administrator for the exact URL and the "
00234             "account details.</p></qt>" ),
00235       i18n( "No Free/Busy Upload URL" ) );
00236     return;
00237   }
00238 
00239   if ( mBrokenUrl ) {
00240      // Url is invalid, don't try again
00241     return;
00242   }
00243   if ( !targetURL.isValid() ) {
00244     KMessageBox::sorry(
00245       0,
00246       i18n( "<qt>The target URL '%1' provided is invalid.</qt>", targetURL.prettyUrl() ),
00247       i18n( "Invalid URL" ) );
00248     mBrokenUrl = true;
00249     return;
00250   }
00251   targetURL.setUser( KOPrefs::instance()->mFreeBusyPublishUser );
00252   targetURL.setPass( KOPrefs::instance()->mFreeBusyPublishPassword );
00253 
00254   mUploadingFreeBusy = true;
00255 
00256   // If we have a timer running, it should be stopped now
00257   if ( mTimerID != 0 ) {
00258     killTimer( mTimerID );
00259     mTimerID = 0;
00260   }
00261 
00262   // Save the time of the next free/busy uploading
00263   mNextUploadTime = QDateTime::currentDateTime();
00264   if ( KOPrefs::instance()->mFreeBusyPublishDelay > 0 ) {
00265     mNextUploadTime = mNextUploadTime.addSecs( KOPrefs::instance()->mFreeBusyPublishDelay * 60 );
00266   }
00267 
00268   QString messageText = ownerFreeBusyAsString();
00269 
00270   // We need to massage the list a bit so that Outlook understands
00271   // it.
00272   messageText = messageText.replace( QRegExp( "ORGANIZER\\s*:MAILTO:" ), "ORGANIZER:" );
00273 
00274   // Create a local temp file and save the message to it
00275   KTemporaryFile tempFile;
00276   tempFile.setAutoRemove( false );
00277   if ( tempFile.open() ) {
00278     QTextStream textStream ( &tempFile );
00279     textStream << messageText;
00280     textStream.flush();
00281 
00282 #if 0
00283     QString defaultEmail = KOCore()::self()->email();
00284     QString emailHost = defaultEmail.mid( defaultEmail.indexOf( '@' ) + 1 );
00285 
00286     // Put target string together
00287     KUrl targetURL;
00288     if( KOPrefs::instance()->mPublishKolab ) {
00289       // we use Kolab
00290       QString server;
00291       if ( KOPrefs::instance()->mPublishKolabServer == QLatin1String( "%SERVER%" ) ||
00292            KOPrefs::instance()->mPublishKolabServer.isEmpty() ) {
00293         server = emailHost;
00294       } else {
00295         server = KOPrefs::instance()->mPublishKolabServer;
00296       }
00297 
00298       targetURL.setProtocol( "webdavs" );
00299       targetURL.setHost( server );
00300 
00301       QString fbname = KOPrefs::instance()->mPublishUserName;
00302       int at = fbname.indexOf( '@' );
00303       if ( at > 1 && fbname.length() > (uint)at ) {
00304         fbname = fbname.left(at);
00305       }
00306       targetURL.setPath( "/freebusy/" + fbname + ".ifb" );
00307       targetURL.setUser( KOPrefs::instance()->mPublishUserName );
00308       targetURL.setPass( KOPrefs::instance()->mPublishPassword );
00309     } else {
00310       // we use something else
00311       targetURL = KOPrefs::instance()->mPublishAnyURL.replace( "%SERVER%", emailHost );
00312       targetURL.setUser( KOPrefs::instance()->mPublishUserName );
00313       targetURL.setPass( KOPrefs::instance()->mPublishPassword );
00314     }
00315 #endif
00316 
00317     KUrl src;
00318     src.setPath( tempFile.fileName() );
00319 
00320     kDebug() << targetURL;
00321 
00322     KIO::Job *job = KIO::file_copy( src, targetURL, -1, KIO::Overwrite | KIO::HideProgressInfo );
00323     connect( job, SIGNAL(result(KJob *)), SLOT(slotUploadFreeBusyResult(KJob *)) );
00324   }
00325 }
00326 
00327 void FreeBusyManager::slotUploadFreeBusyResult( KJob *_job )
00328 {
00329     KIO::FileCopyJob *job = static_cast<KIO::FileCopyJob *>( _job );
00330     if ( job->error() ) {
00331         KMessageBox::sorry(
00332           0,
00333           i18n( "<qt><p>The software could not upload your free/busy list to "
00334                 "the URL '%1'. There might be a problem with the access "
00335                 "rights, or you specified an incorrect URL. The system said: "
00336                 "<em>%2</em>.</p>"
00337                 "<p>Please check the URL or contact your system administrator."
00338                 "</p></qt>", job->destUrl().prettyUrl(),
00339                 job->errorString() ) );
00340     }
00341     // Delete temp file
00342     KUrl src = job->srcUrl();
00343     Q_ASSERT( src.isLocalFile() );
00344     if ( src.isLocalFile() ) {
00345       QFile::remove( src.path() );
00346     }
00347     mUploadingFreeBusy = false;
00348 }
00349 
00350 bool FreeBusyManager::retrieveFreeBusy( const QString &email, bool forceDownload )
00351 {
00352   kDebug() << email;
00353   if ( email.isEmpty() ) {
00354     return false;
00355   }
00356 
00357   if ( KOPrefs::instance()->thatIsMe( email ) ) {
00358     // Don't download our own free-busy list from the net
00359     kDebug() << "freebusy of owner";
00360     emit freeBusyRetrieved( ownerFreeBusy(), email );
00361     return true;
00362   }
00363 
00364   // Check for cached copy of free/busy list
00365   KCal::FreeBusy *fb = loadFreeBusy( email );
00366   if ( fb ) {
00367     emit freeBusyRetrieved( fb, email );
00368   }
00369 
00370   // Don't download free/busy if the user does not want it.
00371   if ( !KOPrefs::instance()->mFreeBusyRetrieveAuto && !forceDownload ) {
00372     return false;
00373   }
00374 
00375   mRetrieveQueue.append( email );
00376 
00377   if ( mRetrieveQueue.count() > 1 ) {
00378     return true;
00379   }
00380 
00381   return processRetrieveQueue();
00382 }
00383 
00384 bool FreeBusyManager::processRetrieveQueue()
00385 {
00386   if ( mRetrieveQueue.isEmpty() ) {
00387     return true;
00388   }
00389 
00390   QString email = mRetrieveQueue.first();
00391   mRetrieveQueue.pop_front();
00392 
00393   KUrl sourceURL = freeBusyUrl( email );
00394 
00395   kDebug() << "url:" << sourceURL;
00396 
00397   if ( !sourceURL.isValid() ) {
00398     kDebug() << "Invalid FB URL";
00399     return false;
00400   }
00401 
00402   FreeBusyDownloadJob *job = new FreeBusyDownloadJob( email, sourceURL, this );
00403   job->setObjectName( "freebusy_download_job" );
00404   connect( job, SIGNAL(freeBusyDownloaded(KCal::FreeBusy *,const QString &)),
00405            SIGNAL(freeBusyRetrieved(KCal::FreeBusy *,const QString &)) );
00406   connect( job, SIGNAL(freeBusyDownloaded(KCal::FreeBusy *,const QString &)),
00407            SLOT(processRetrieveQueue()) );
00408 
00409   return true;
00410 }
00411 
00412 void FreeBusyManager::cancelRetrieval()
00413 {
00414   mRetrieveQueue.clear();
00415 }
00416 
00417 KUrl FreeBusyManager::freeBusyUrl( const QString &email ) const
00418 {
00419   kDebug() << email;
00420 
00421   // First check if there is a specific FB url for this email
00422   QString configFile = KStandardDirs::locateLocal( "data", "korganizer/freebusyurls" );
00423   KConfig cfg( configFile );
00424   KConfigGroup group = cfg.group(email);
00425   QString url = group.readEntry( "url" );
00426   if ( !url.isEmpty() ) {
00427     return KUrl( url );
00428   }
00429   // Try with the url configurated by preferred email in kaddressbook
00430   KABC::Addressee::List list= KABC::StdAddressBook::self( true )->findByEmail( email );
00431   KABC::Addressee::List::Iterator it;
00432   QString pref;
00433   for ( it = list.begin(); it != list.end(); ++it ) {
00434     pref = (*it).preferredEmail();
00435     if ( !pref.isEmpty() && pref != email ) {
00436       kDebug() << "Preferred email of" << email << "is" << pref;
00437       group = cfg.group( pref );
00438       url = group.readEntry ( "url" );
00439       if ( !url.isEmpty() ) {
00440         kDebug() << "Taken url from preferred email:" << url;
00441         return KUrl( url );
00442       }
00443     }
00444   }
00445   // None found. Check if we do automatic FB retrieving then
00446   if ( !KOPrefs::instance()->mFreeBusyRetrieveAuto ) {
00447     // No, so no FB list here
00448     return KUrl();
00449   }
00450 
00451   // Sanity check: Don't download if it's not a correct email
00452   // address (this also avoids downloading for "(empty email)").
00453   int emailpos = email.indexOf( '@' );
00454   if( emailpos == -1 ) {
00455      kDebug() << "No '@' found in" << email;
00456      return KUrl();
00457   }
00458 
00459   // Cut off everything left of the @ sign to get the user name.
00460   const QString emailName = email.left( emailpos );
00461   const QString emailHost = email.mid( emailpos + 1 );
00462 
00463   // Build the URL
00464   KUrl sourceURL;
00465   sourceURL = KOPrefs::instance()->mFreeBusyRetrieveUrl;
00466 
00467   if ( KOPrefs::instance()->mFreeBusyCheckHostname ) {
00468     // Don't try to fetch free/busy data for users not on the specified servers
00469     // This tests if the hostnames match, or one is a subset of the other
00470     const QString hostDomain = sourceURL.host();
00471     if ( hostDomain != emailHost &&
00472          !hostDomain.endsWith( '.' + emailHost ) &&
00473          !emailHost.endsWith( '.' + hostDomain ) ) {
00474       // Host names do not match
00475       kDebug() << "Host '" << sourceURL.host()
00476                << "' doesn't match email '" << email << '\'';
00477       return KUrl();
00478     }
00479   }
00480 
00481   if ( KOPrefs::instance()->mFreeBusyFullDomainRetrieval ) {
00482     sourceURL.setFileName( email + ".ifb" );
00483   } else {
00484     sourceURL.setFileName( emailName + ".ifb" );
00485   }
00486   sourceURL.setUser( KOPrefs::instance()->mFreeBusyRetrieveUser );
00487   sourceURL.setPass( KOPrefs::instance()->mFreeBusyRetrievePassword );
00488 
00489   return sourceURL;
00490 }
00491 
00492 KCal::FreeBusy *FreeBusyManager::iCalToFreeBusy( const QByteArray &data )
00493 {
00494   kDebug() << data;
00495 
00496   QString freeBusyVCal = QString::fromUtf8( data );
00497   KCal::FreeBusy *fb = mFormat.parseFreeBusy( freeBusyVCal );
00498   if ( !fb ) {
00499     kDebug() << "Error parsing free/busy";
00500     kDebug() << freeBusyVCal;
00501   }
00502   return fb;
00503 }
00504 
00505 QString FreeBusyManager::freeBusyDir()
00506 {
00507   return KStandardDirs::locateLocal( "data", "korganizer/freebusy" );
00508 }
00509 
00510 FreeBusy *FreeBusyManager::loadFreeBusy( const QString &email )
00511 {
00512   kDebug() << email;
00513 
00514   QString fbd = freeBusyDir();
00515 
00516   QFile f( fbd + '/' + email + ".ifb" );
00517   if ( !f.exists() ) {
00518     kDebug() << f.fileName() << "doesn't exist.";
00519     return 0;
00520   }
00521 
00522   if ( !f.open( QIODevice::ReadOnly ) ) {
00523     kDebug() << "Unable to open file" << f.fileName();
00524     return 0;
00525   }
00526 
00527   QTextStream ts( &f );
00528   QString str = ts.readAll();
00529 
00530   return iCalToFreeBusy( str.toUtf8() );
00531 }
00532 
00533 bool FreeBusyManager::saveFreeBusy( FreeBusy *freebusy, const Person &person )
00534 {
00535   kDebug() << person.fullName();
00536 
00537   QString fbd = freeBusyDir();
00538 
00539   QDir freeBusyDirectory( fbd );
00540   if ( !freeBusyDirectory.exists() ) {
00541     kDebug() << "Directory" << fbd <<" does not exist!";
00542     kDebug() << "Creating directory:" << fbd;
00543 
00544     if( !freeBusyDirectory.mkpath( fbd ) ) {
00545       kDebug() << "Could not create directory:" << fbd;
00546       return false;
00547     }
00548   }
00549 
00550   QString filename( fbd );
00551   filename += '/';
00552   filename += person.email();
00553   filename += ".ifb";
00554   QFile f( filename );
00555 
00556   kDebug() << "filename:" << filename;
00557 
00558   freebusy->clearAttendees();
00559   freebusy->setOrganizer( person );
00560 
00561   QString messageText = mFormat.createScheduleMessage( freebusy, iTIPPublish );
00562 
00563   if ( !f.open( QIODevice::ReadWrite ) ) {
00564     kDebug() << "acceptFreeBusy: Can't open:" << filename << "for writing";
00565     return false;
00566   }
00567   QTextStream t( &f );
00568   t << messageText;
00569   f.close();
00570 
00571   return true;
00572 }
00573 
00574 #include "freebusymanager.moc"

korganizer

Skip menu "korganizer"
  • Main Page
  • Namespace List
  • Class Hierarchy
  • Alphabetical List
  • Class List
  • File List
  • Class Members

kdepim

Skip menu "kdepim"
  • akonadi
  •   clients
  •   kabc
  •   kcal
  •   kcm
  • akregator
  • console
  •   kabcclient
  •   konsolekalendar
  • kaddressbook
  • kalarm
  •   lib
  • kdgantt
  • kdgantt1
  • kjots
  • kleopatra
  • kmail
  • kmobiletools
  • knode
  • knotes
  • kontact
  • kontactinterfaces
  • korganizer
  •   korgac
  • kpilot
  • ktimetracker
  •   doc
  • libkdepim
  • libkholidays
  • libkleo
  • libkpgp
  • maildir
Generated for kdepim by doxygen 1.5.4
This website is maintained by Adriaan de Groot and Allen Winter.
KDE® and the K Desktop Environment® logo are registered trademarks of KDE e.V. | Legal