00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030
00031
00032
00033
00034
00035
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/jobclasses.h>
00055 #include <kio/netaccess.h>
00056 #include <kio/scheduler.h>
00057 #include <kapplication.h>
00058 #include <kconfig.h>
00059 #include <klocale.h>
00060 #include <kstandarddirs.h>
00061 #include <kabc/stdaddressbook.h>
00062 #include <kabc/addressee.h>
00063
00064 #include <qfile.h>
00065 #include <qbuffer.h>
00066 #include <qregexp.h>
00067 #include <qdir.h>
00068
00069 using namespace KCal;
00070
00071 FreeBusyDownloadJob::FreeBusyDownloadJob( const QString &email, const KURL &url,
00072 FreeBusyManager *manager,
00073 const char *name )
00074 : QObject( manager, name ), mManager( manager ), mEmail( email )
00075 {
00076 KIO::TransferJob *job = KIO::get( url, false, false );
00077 connect( job, SIGNAL( result( KIO::Job * ) ),
00078 SLOT( slotResult( KIO::Job * ) ) );
00079 connect( job, SIGNAL( data( KIO::Job *, const QByteArray & ) ),
00080 SLOT( slotData( KIO::Job *, const QByteArray & ) ) );
00081 KIO::Scheduler::scheduleJob( job );
00082 }
00083
00084 FreeBusyDownloadJob::~FreeBusyDownloadJob()
00085 {
00086 }
00087
00088
00089 void FreeBusyDownloadJob::slotData( KIO::Job *, const QByteArray &data )
00090 {
00091 QByteArray tmp = data;
00092 tmp.resize( tmp.size() + 1 );
00093 tmp[tmp.size()-1] = 0;
00094 mFreeBusyData += tmp;
00095 }
00096
00097 void FreeBusyDownloadJob::slotResult( KIO::Job *job )
00098 {
00099 kdDebug(5850) << "FreeBusyDownloadJob::slotResult() " << mEmail << endl;
00100
00101 if( job->error() ) {
00102 kdDebug(5850) << "FreeBusyDownloadJob::slotResult() job error for " << mEmail << endl;
00103 emit freeBusyDownloadError( mEmail );
00104 } else {
00105 FreeBusy *fb = mManager->iCalToFreeBusy( mFreeBusyData );
00106 if ( fb ) {
00107 Person p = fb->organizer();
00108 p.setEmail( mEmail );
00109 mManager->saveFreeBusy( fb, p );
00110 }
00111 emit freeBusyDownloaded( fb, mEmail );
00112 }
00113 deleteLater();
00114 }
00115
00117
00118 FreeBusyManager::FreeBusyManager( QObject *parent, const char *name )
00119 : QObject( parent, name ),
00120 mCalendar( 0 ), mTimerID( 0 ), mUploadingFreeBusy( false ),
00121 mBrokenUrl( false )
00122 {
00123 }
00124
00125 void FreeBusyManager::setCalendar( KCal::Calendar *c )
00126 {
00127 mCalendar = c;
00128 if ( mCalendar ) {
00129 mFormat.setTimeZone( mCalendar->timeZoneId(), true );
00130 }
00131 }
00132
00133 KCal::FreeBusy *FreeBusyManager::ownerFreeBusy()
00134 {
00135 QDateTime start = QDateTime::currentDateTime();
00136 QDateTime end = start.addDays( KOPrefs::instance()->mFreeBusyPublishDays );
00137
00138 FreeBusy *freebusy = new FreeBusy( mCalendar, start, end );
00139 freebusy->setOrganizer( Person( KOPrefs::instance()->fullName(),
00140 KOPrefs::instance()->email() ) );
00141
00142 return freebusy;
00143 }
00144
00145 QString FreeBusyManager::ownerFreeBusyAsString()
00146 {
00147 FreeBusy *freebusy = ownerFreeBusy();
00148
00149 QString result = freeBusyToIcal( freebusy );
00150
00151 delete freebusy;
00152
00153 return result;
00154 }
00155
00156 QString FreeBusyManager::freeBusyToIcal( KCal::FreeBusy *freebusy )
00157 {
00158 return mFormat.createScheduleMessage( freebusy, Scheduler::Publish );
00159 }
00160
00161 void FreeBusyManager::slotPerhapsUploadFB()
00162 {
00163
00164 if ( !KOPrefs::instance()->freeBusyPublishAuto() ||
00165 KOPrefs::instance()->freeBusyPublishUrl().isEmpty() )
00166 return;
00167 if( mTimerID != 0 )
00168
00169 return;
00170
00171 int now = static_cast<int>( QDateTime::currentDateTime().toTime_t() );
00172 int eta = static_cast<int>( mNextUploadTime.toTime_t() ) - now;
00173
00174 if( !mUploadingFreeBusy ) {
00175
00176 if( mNextUploadTime.isNull() ||
00177 QDateTime::currentDateTime() > mNextUploadTime ) {
00178
00179 publishFreeBusy();
00180 return;
00181 }
00182
00183
00184 if( eta <= 0 ) {
00185
00186 publishFreeBusy();
00187 return;
00188 }
00189 } else {
00190
00191 if( eta <= 0 ) {
00192 kdDebug(5850) << "This shouldn't happen! eta <= 0\n";
00193 eta = 10;
00194 }
00195 }
00196
00197
00198 mTimerID = startTimer( eta * 1000 );
00199
00200 if( mTimerID == 0 )
00201
00202 publishFreeBusy();
00203 }
00204
00205
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
00223 if ( mUploadingFreeBusy )
00224 return;
00225 KURL targetURL ( KOPrefs::instance()->freeBusyPublishUrl() );
00226 if ( targetURL.isEmpty() ) {
00227 KMessageBox::sorry( 0,
00228 i18n( "<qt>No URL configured for uploading your free/busy list. Please "
00229 "set it in KOrganizer's configuration dialog, on the \"Free/Busy\" page. "
00230 "<br>Contact your system administrator for the exact URL and the "
00231 "account details."
00232 "</qt>" ), i18n("No Free/Busy Upload URL") );
00233 return;
00234 }
00235 if ( mBrokenUrl )
00236 return;
00237 if ( !targetURL.isValid() ) {
00238 KMessageBox::sorry( 0,
00239 i18n( "<qt>The target URL '%1' provided is invalid."
00240 "</qt>" ).arg( targetURL.prettyURL() ), i18n("Invalid URL") );
00241 mBrokenUrl = true;
00242 return;
00243 }
00244 targetURL.setUser( KOPrefs::instance()->mFreeBusyPublishUser );
00245 targetURL.setPass( KOPrefs::instance()->mFreeBusyPublishPassword );
00246
00247 mUploadingFreeBusy = true;
00248
00249
00250 if( mTimerID != 0 ) {
00251 killTimer( mTimerID );
00252 mTimerID = 0;
00253 }
00254
00255
00256 mNextUploadTime = QDateTime::currentDateTime();
00257 if( KOPrefs::instance()->mFreeBusyPublishDelay > 0 )
00258 mNextUploadTime = mNextUploadTime.addSecs(
00259 KOPrefs::instance()->mFreeBusyPublishDelay * 60 );
00260
00261 QString messageText = ownerFreeBusyAsString();
00262
00263
00264
00265 messageText = messageText.replace( QRegExp( "ORGANIZER\\s*:MAILTO:" ),
00266 "ORGANIZER:" );
00267
00268
00269 KTempFile tempFile;
00270 QTextStream *textStream = tempFile.textStream();
00271 if( textStream ) {
00272 *textStream << messageText;
00273 tempFile.close();
00274
00275 #if 0
00276 QString defaultEmail = KOCore()::self()->email();
00277 QString emailHost = defaultEmail.mid( defaultEmail.find( '@' ) + 1 );
00278
00279
00280 KURL targetURL;
00281 if( KOPrefs::instance()->mPublishKolab ) {
00282
00283 QString server;
00284 if( KOPrefs::instance()->mPublishKolabServer == "%SERVER%" ||
00285 KOPrefs::instance()->mPublishKolabServer.isEmpty() )
00286 server = emailHost;
00287 else
00288 server = KOPrefs::instance()->mPublishKolabServer;
00289
00290 targetURL.setProtocol( "webdavs" );
00291 targetURL.setHost( server );
00292
00293 QString fbname = KOPrefs::instance()->mPublishUserName;
00294 int at = fbname.find('@');
00295 if( at > 1 && fbname.length() > (uint)at ) {
00296 fbname = fbname.left(at);
00297 }
00298 targetURL.setPath( "/freebusy/" + fbname + ".ifb" );
00299 targetURL.setUser( KOPrefs::instance()->mPublishUserName );
00300 targetURL.setPass( KOPrefs::instance()->mPublishPassword );
00301 } else {
00302
00303 targetURL = KOPrefs::instance()->mPublishAnyURL.replace( "%SERVER%",
00304 emailHost );
00305 targetURL.setUser( KOPrefs::instance()->mPublishUserName );
00306 targetURL.setPass( KOPrefs::instance()->mPublishPassword );
00307 }
00308 #endif
00309
00310
00311 KURL src;
00312 src.setPath( tempFile.name() );
00313
00314 kdDebug(5850) << "FreeBusyManager::publishFreeBusy(): " << targetURL << endl;
00315
00316 KIO::Job * job = KIO::file_copy( src, targetURL, -1,
00317 true ,
00318 false ,
00319 false );
00320 connect( job, SIGNAL( result( KIO::Job * ) ),
00321 SLOT( slotUploadFreeBusyResult( KIO::Job * ) ) );
00322 }
00323 }
00324
00325 void FreeBusyManager::slotUploadFreeBusyResult(KIO::Job *_job)
00326 {
00327 KIO::FileCopyJob* job = static_cast<KIO::FileCopyJob *>(_job);
00328 if ( job->error() )
00329 KMessageBox::sorry( 0,
00330 i18n( "<qt>The software could not upload your free/busy list to the "
00331 "URL '%1'. There might be a problem with the access rights, or "
00332 "you specified an incorrect URL. The system said: <em>%2</em>."
00333 "<br>Please check the URL or contact your system administrator."
00334 "</qt>" ).arg( job->destURL().prettyURL() )
00335 .arg( job->errorString() ) );
00336
00337 KURL src = job->srcURL();
00338 Q_ASSERT( src.isLocalFile() );
00339 if( src.isLocalFile() )
00340 QFile::remove(src.path());
00341 mUploadingFreeBusy = false;
00342 }
00343
00344 bool FreeBusyManager::retrieveFreeBusy( const QString &email, bool forceDownload )
00345 {
00346 kdDebug(5850) << "FreeBusyManager::retrieveFreeBusy(): " << email << endl;
00347 if ( email.isEmpty() ) return false;
00348
00349
00350 KCal::FreeBusy *fb = loadFreeBusy( email );
00351 if ( fb ) {
00352 emit freeBusyRetrieved( fb, email );
00353 }
00354
00355
00356 if( !KOPrefs::instance()->mFreeBusyRetrieveAuto && !forceDownload) {
00357 slotFreeBusyDownloadError( email );
00358 return false;
00359 }
00360
00361 mRetrieveQueue.append( email );
00362
00363 if ( mRetrieveQueue.count() > 1 ) return true;
00364
00365 return processRetrieveQueue();
00366 }
00367
00368 bool FreeBusyManager::processRetrieveQueue()
00369 {
00370 if ( mRetrieveQueue.isEmpty() ) return true;
00371
00372 QString email = mRetrieveQueue.first();
00373 mRetrieveQueue.pop_front();
00374
00375 KURL sourceURL = freeBusyUrl( email );
00376
00377 kdDebug(5850) << "FreeBusyManager::processRetrieveQueue(): url: " << sourceURL
00378 << endl;
00379
00380 if ( !sourceURL.isValid() ) {
00381 kdDebug(5850) << "Invalid FB URL\n";
00382 slotFreeBusyDownloadError( email );
00383 return false;
00384 }
00385
00386 FreeBusyDownloadJob *job = new FreeBusyDownloadJob( email, sourceURL, this,
00387 "freebusy_download_job" );
00388 connect( job, SIGNAL( freeBusyDownloaded( KCal::FreeBusy *,
00389 const QString & ) ),
00390 SIGNAL( freeBusyRetrieved( KCal::FreeBusy *, const QString & ) ) );
00391 connect( job, SIGNAL( freeBusyDownloaded( KCal::FreeBusy *,
00392 const QString & ) ),
00393 SLOT( processRetrieveQueue() ) );
00394
00395 connect( job, SIGNAL( freeBusyDownloadError( const QString& ) ),
00396 this, SLOT( slotFreeBusyDownloadError( const QString& ) ) );
00397
00398 return true;
00399 }
00400
00401 void FreeBusyManager::slotFreeBusyDownloadError( const QString& email )
00402 {
00403 if( KOPrefs::instance()->thatIsMe( email ) ) {
00404
00405
00406
00407
00408
00409 kdDebug(5850) << "freebusy of owner, falling back to local list" << endl;
00410 emit freeBusyRetrieved( ownerFreeBusy(), email );
00411 }
00412
00413 }
00414
00415 void FreeBusyManager::cancelRetrieval()
00416 {
00417 mRetrieveQueue.clear();
00418 }
00419
00420 KURL FreeBusyManager::freeBusyUrl( const QString &email )
00421 {
00422 kdDebug(5850) << "FreeBusyManager::freeBusyUrl(): " << email << endl;
00423
00424
00425 QString configFile = locateLocal( "data", "korganizer/freebusyurls" );
00426 KConfig cfg( configFile );
00427
00428 cfg.setGroup( email );
00429 QString url = cfg.readEntry( "url" );
00430 if ( !url.isEmpty() ) {
00431 kdDebug(5850) << "found cached url: " << url << endl;
00432 return KURL( url );
00433 }
00434
00435 KABC::Addressee::List list= KABC::StdAddressBook::self( true )->findByEmail( email );
00436 KABC::Addressee::List::Iterator it;
00437 QString pref;
00438 for ( it = list.begin(); it != list.end(); ++it ) {
00439 pref = (*it).preferredEmail();
00440 if ( !pref.isEmpty() && pref != email ) {
00441 kdDebug( 5850 ) << "FreeBusyManager::freeBusyUrl():" <<
00442 "Preferred email of " << email << " is " << pref << endl;
00443 cfg.setGroup( pref );
00444 url = cfg.readEntry ( "url" );
00445 if ( !url.isEmpty() ) {
00446 kdDebug( 5850 ) << "FreeBusyManager::freeBusyUrl():" <<
00447 "Taken url from preferred email:" << url << endl;
00448 return KURL( url );
00449 }
00450 }
00451 }
00452
00453 if ( !KOPrefs::instance()->mFreeBusyRetrieveAuto ) {
00454 kdDebug( 5850 ) << "no auto retrieving" << endl;
00455
00456 return KURL();
00457 }
00458
00459
00460
00461 int emailpos = email.find( '@' );
00462 if( emailpos == -1 )
00463 return KURL();
00464
00465
00466 const QString emailName = email.left( emailpos );
00467 const QString emailHost = email.mid( emailpos + 1 );
00468
00469
00470 KURL sourceURL;
00471 sourceURL = KOPrefs::instance()->mFreeBusyRetrieveUrl;
00472
00473 if ( KOPrefs::instance()->mFreeBusyCheckHostname ) {
00474
00475
00476 const QString hostDomain = sourceURL.host();
00477 if ( hostDomain != emailHost && !hostDomain.endsWith( '.' + emailHost )
00478 && !emailHost.endsWith( '.' + hostDomain ) ) {
00479
00480 kdDebug(5850) << "Host '" << sourceURL.host() << "' doesn't match email '"
00481 << email << '\'' << endl;
00482 return KURL();
00483 }
00484 }
00485
00486 kdDebug(5850) << "Server FreeBusy url: " << sourceURL << endl;
00487 if ( KOPrefs::instance()->mFreeBusyFullDomainRetrieval )
00488 sourceURL.setFileName( email + ".ifb" );
00489 else
00490 sourceURL.setFileName( emailName + ".ifb" );
00491 sourceURL.setUser( KOPrefs::instance()->mFreeBusyRetrieveUser );
00492 sourceURL.setPass( KOPrefs::instance()->mFreeBusyRetrievePassword );
00493
00494 kdDebug(5850) << "Results in generated: " << sourceURL << endl;
00495 return sourceURL;
00496 }
00497
00498 KCal::FreeBusy *FreeBusyManager::iCalToFreeBusy( const QCString &data )
00499 {
00500 kdDebug(5850) << "FreeBusyManager::iCalToFreeBusy()" << endl;
00501 kdDebug(5850) << data << endl;
00502
00503 QString freeBusyVCal = QString::fromUtf8( data );
00504 KCal::FreeBusy *fb = mFormat.parseFreeBusy( freeBusyVCal );
00505 if ( !fb ) {
00506 kdDebug(5850) << "FreeBusyManager::iCalToFreeBusy(): Error parsing free/busy"
00507 << endl;
00508 kdDebug(5850) << freeBusyVCal << endl;
00509 }
00510 return fb;
00511 }
00512
00513 QString FreeBusyManager::freeBusyDir()
00514 {
00515 return locateLocal( "data", "korganizer/freebusy" );
00516 }
00517
00518 FreeBusy *FreeBusyManager::loadFreeBusy( const QString &email )
00519 {
00520 kdDebug(5850) << "FreeBusyManager::loadFreeBusy(): " << email << endl;
00521
00522 QString fbd = freeBusyDir();
00523
00524 QFile f( fbd + "/" + email + ".ifb" );
00525 if ( !f.exists() ) {
00526 kdDebug(5850) << "FreeBusyManager::loadFreeBusy() " << f.name()
00527 << " doesn't exist." << endl;
00528 return 0;
00529 }
00530
00531 if ( !f.open( IO_ReadOnly ) ) {
00532 kdDebug(5850) << "FreeBusyManager::loadFreeBusy() Unable to open file "
00533 << f.name() << endl;
00534 return 0;
00535 }
00536
00537 QTextStream ts( &f );
00538 QString str = ts.read();
00539
00540 return iCalToFreeBusy( str.utf8() );
00541 }
00542
00543 bool FreeBusyManager::saveFreeBusy( FreeBusy *freebusy, const Person &person )
00544 {
00545 kdDebug(5850) << "FreeBusyManager::saveFreeBusy(): " << person.fullName() << endl;
00546
00547 QString fbd = freeBusyDir();
00548
00549 QDir freeBusyDirectory( fbd );
00550 if ( !freeBusyDirectory.exists() ) {
00551 kdDebug(5850) << "Directory " << fbd << " does not exist!" << endl;
00552 kdDebug(5850) << "Creating directory: " << fbd << endl;
00553
00554 if( !freeBusyDirectory.mkdir( fbd, true ) ) {
00555 kdDebug(5850) << "Could not create directory: " << fbd << endl;
00556 return false;
00557 }
00558 }
00559
00560 QString filename( fbd );
00561 filename += "/";
00562 filename += person.email();
00563 filename += ".ifb";
00564 QFile f( filename );
00565
00566 kdDebug(5850) << "FreeBusyManager::saveFreeBusy(): filename: " << filename
00567 << endl;
00568
00569 freebusy->clearAttendees();
00570 freebusy->setOrganizer( person );
00571
00572 QString messageText = mFormat.createScheduleMessage( freebusy,
00573 Scheduler::Publish );
00574
00575 if ( !f.open( IO_ReadWrite ) ) {
00576 kdDebug(5850) << "acceptFreeBusy: Can't open:" << filename << " for writing"
00577 << endl;
00578 return false;
00579 }
00580 QTextStream t( &f );
00581 t << messageText;
00582 f.close();
00583
00584 return true;
00585 }
00586
00587 #include "freebusymanager.moc"