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