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