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