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