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