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