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 #include "kogroupware.h"
00030 #include "koprefs.h"
00031 #include "calendarview.h"
00032 #include "mailscheduler.h"
00033 #include "kogroupwareincomingdialog.h"
00034 #include "koviewmanager.h"
00035
00036 #include <libkcal/incidencebase.h>
00037 #include <libkcal/attendee.h>
00038 #include <libkcal/freebusy.h>
00039 #include <libkcal/journal.h>
00040
00041 #include <kdebug.h>
00042 #include <kmessagebox.h>
00043 #include <ktempfile.h>
00044 #include <kio/netaccess.h>
00045 #include <kapplication.h>
00046 #include <kconfig.h>
00047 #include <dcopclient.h>
00048 #include <dcopref.h>
00049
00050 #include <qfile.h>
00051 #include <qregexp.h>
00052
00053 #include <mimelib/enum.h>
00054
00055 KOGroupware* KOGroupware::mInstance = 0;
00056
00057 KOGroupware* KOGroupware::create( CalendarView* view, KCal::Calendar* calendar )
00058 {
00059 if( !mInstance )
00060 mInstance = new KOGroupware( view, calendar );
00061 return mInstance;
00062 }
00063
00064 KOGroupware* KOGroupware::instance()
00065 {
00066
00067 Q_ASSERT( mInstance );
00068 return mInstance;
00069 }
00070
00071
00072 KOGroupware::KOGroupware( CalendarView* view, KCal::Calendar* calendar )
00073 : QObject( 0, "kmgroupware_instance" )
00074 {
00075 mView = view;
00076 mCalendar = calendar;
00077
00078
00079 }
00080
00081
00107 bool KOGroupware::incomingEventRequest( const QString& request,
00108 const QCString& receiver,
00109 const QString& vCalIn )
00110 {
00111 EventState state;
00112 if( request == "accept" )
00113 state = Accepted;
00114 else if( request == "accept conditionally" )
00115 state = ConditionallyAccepted;
00116 else if( request == "decline" )
00117 state = Declined;
00118 else if( request == "check" )
00119 state = Request;
00120 else
00121 return false;
00122
00123
00124
00125 KCal::ScheduleMessage *message = mFormat.parseScheduleMessage( mCalendar,
00126 vCalIn );
00127 if( message ) {
00128 kdDebug(5850) << "KOGroupware::incomingEventRequest: got message '"
00129 << vCalIn << "'" << endl;
00130 } else {
00131 QString errorMessage;
00132 if( mFormat.exception() ) {
00133 errorMessage = mFormat.exception()->message();
00134 }
00135 kdDebug(5850) << "KOGroupware::incomingEventRequest() Error parsing "
00136 << "message: " << errorMessage << endl;
00137
00138 return false;
00139 }
00140
00141 KCal::Incidence* event = dynamic_cast<KCal::Incidence*>( message->event() );
00142 Q_ASSERT( event );
00143 if( !event ) {
00144 kdDebug(5850) << "KOGroupware::incomingEventRequest(): Not an event???\n";
00145 return false;
00146 }
00147
00148
00149
00150 if( state == Request ) {
00151
00152 KOGroupwareIncomingDialog dlg( event );
00153 int ret = dlg.exec();
00154 if( ret == QDialog::Rejected ) {
00155
00156 kdDebug(5850) << "KOGroupware::incomingEventRequest(): User canceled\n";
00157 return false;
00158 }
00159
00160 if( dlg.isDeclined() )
00161 state = Declined;
00162 else if( dlg.isConditionallyAccepted() )
00163 state = ConditionallyAccepted;
00164 else if( dlg.isAccepted() )
00165 state = Accepted;
00166 else
00167 kdDebug(5850) << "KOGroupware::incomingEventRequest(): unknown "
00168 << "event request state" << endl;
00169 }
00170
00171
00172
00173 #if 0
00174
00175
00176 Alarm::List alarms = event->alarms();
00177 Alarm::List::ConstIterator it;
00178 for ( it = alarms.begin(); it != alarms.end(); ++it) {
00179 if ( (*it)->hasTime() ) {
00180 QDateTime t = (*it)->time();
00181 int offset = event->dtStart().secsTo( t );
00182 if( offset > 0 )
00183
00184 kdDebug(5850) << "Warning: Alarm fires after the event\n";
00185 } else {
00186 int offset = (*it)->offset().asSeconds();
00187 if( offset > 0 ) {
00188
00189 Duration d( -offset );
00190 (*it)->setOffset( d );
00191 }
00192 }
00193 }
00194 #endif
00195
00196
00197
00198
00199
00200
00201 KCal::MailScheduler scheduler( mCalendar );
00202 if( state == Accepted || state == ConditionallyAccepted ) {
00203 scheduler.acceptTransaction( event,
00204 (KCal::Scheduler::Method)message->method(),
00205 message->status() );
00206 mView->updateView();
00207 }
00208
00209 KCal::Attendee::List attendees = event->attendees();
00210 KCal::Attendee::List::ConstIterator it;
00211 KCal::Attendee* myself = 0;
00212
00213
00214 for ( it = attendees.begin(); it != attendees.end(); ++it ) {
00215 if( (*it)->email().utf8() == receiver ) {
00216
00217
00218 myself = (*it);
00219 break;
00220 }
00221
00222 if( (*it)->email() == KOPrefs::instance()->email() ) {
00223
00224
00225 myself = (*it);
00226 }
00227 }
00228
00229 Q_ASSERT( myself );
00230
00231 KCal::Attendee* newMyself = 0;
00232 if( myself ) {
00233 switch( state ) {
00234 case Accepted:
00235 myself->setStatus( KCal::Attendee::Accepted );
00236 break;
00237 case ConditionallyAccepted:
00238 myself->setStatus( KCal::Attendee::Tentative );
00239 break;
00240 case Declined:
00241 myself->setStatus( KCal::Attendee::Declined );
00242 break;
00243 default:
00244 ;
00245 };
00246
00247
00248 myself->setRSVP(false);
00249
00250 event->updated();
00251
00252 newMyself = new KCal::Attendee( myself->name(),
00253 receiver.isEmpty() ?
00254 myself->email() :
00255 receiver,
00256 myself->RSVP(),
00257 myself->status(),
00258 myself->role(),
00259 myself->uid() );
00260 }
00261
00262 event->updated();
00263
00264
00265
00266
00267
00268
00269
00270
00271 Incidence* newIncidence = event->clone();
00272 Event* newEvent = static_cast<KCal::Event*>( newIncidence );
00273
00274 #if 0
00275
00276
00277
00278
00279 bool stripAlarms = false;
00280 emit getStripAlarmsForSending( stripAlarms );
00281 if( stripAlarms )
00282
00283 newEvent->clearAlarms();
00284 #endif
00285
00286 newEvent->clearAttendees();
00287 if( newMyself )
00288 newEvent->addAttendee( newMyself );
00289
00290
00291 QString messageText = mFormat.createScheduleMessage( newEvent,
00292 KCal::Scheduler::Reply );
00293 scheduler.performTransaction( newEvent, KCal::Scheduler::Reply );
00294
00295
00296 if( vCalIn.contains( "PRODID:-//Microsoft" ) ) {
00297
00298 Attendee* organizer = new KCal::Attendee( i18n("Organizer"),
00299 event->organizer(), false,
00300 KCal::Attendee::Accepted );
00301 event->addAttendee( organizer );
00302 }
00303
00304 kdDebug(5850) << "Done" << endl;
00305 return true;
00306 }
00307
00308
00313 void KOGroupware::incomingResourceRequest( const QValueList<QPair<QDateTime, QDateTime> >& busy,
00314 const QCString& resource,
00315 const QString& vCalIn,
00316 bool& vCalInOK,
00317 QString& vCalOut,
00318 bool& vCalOutOK,
00319 bool& isFree,
00320 QDateTime& start,
00321 QDateTime& end )
00322 {
00323
00324
00325 KCal::ScheduleMessage *message = mFormat.parseScheduleMessage( mCalendar,
00326 vCalIn );
00327 if( message )
00328 vCalInOK = true;
00329 else {
00330 QString errorMessage;
00331 if( mFormat.exception() ) {
00332 errorMessage = mFormat.exception()->message();
00333 }
00334 kdDebug(5850) << "KOGroupware::incomingResourceRequest() Error parsing "
00335 "message: " << errorMessage << endl;
00336 vCalInOK = false;
00337
00338 return;
00339 }
00340
00341 KCal::Event* event = dynamic_cast<KCal::Event*>( message->event() );
00342 Q_ASSERT( event );
00343 if( !event ) {
00344
00345 vCalInOK = false;
00346 return;
00347 }
00348
00349
00350
00351 start = event->dtStart();
00352 end = event->dtEnd();
00353 isFree = true;
00354 for( QValueList<QPair<QDateTime, QDateTime> >::ConstIterator it = busy.begin();
00355 it != busy.end(); ++it ) {
00356 if( (*it).second <= start ||
00357 (*it).first >= end )
00358 continue;
00359 else {
00360 isFree = false;
00361 break;
00362 }
00363 }
00364
00365
00366 KCal::Attendee::List attendees = event->attendees();
00367 KCal::Attendee* resourceAtt = 0;
00368
00369
00370
00371 KCal::Attendee::List::ConstIterator it;
00372 for( it = attendees.begin(); it != attendees.end(); ++it ) {
00373 if( (*it)->email().utf8() == resource ) {
00374 resourceAtt = *it;
00375 break;
00376 }
00377 }
00378 Q_ASSERT( resourceAtt );
00379 if( resourceAtt ) {
00380 if( isFree )
00381 resourceAtt->setStatus( KCal::Attendee::Accepted );
00382 else
00383 resourceAtt->setStatus( KCal::Attendee::Declined );
00384 } else {
00385 vCalOutOK = false;
00386 return;
00387 }
00388
00389
00390 QString messageText = mFormat.createScheduleMessage( event,
00391 KCal::Scheduler::Reply );
00392
00393 vCalOut = messageText;
00394 vCalOutOK = true;
00395 return;
00396 }
00397
00398
00403 bool KOGroupware::incidenceAnswer( const QString& vCal )
00404 {
00405
00406 KCal::ScheduleMessage *message = mFormat.parseScheduleMessage( mCalendar,
00407 vCal );
00408 if( !message ) {
00409
00410 KMessageBox::error( mView, i18n("<b>There was a problem parsing the iCal data:</b><br>%1")
00411 .arg(mFormat.exception()->message()) );
00412 return false;
00413 }
00414
00415 KCal::IncidenceBase* incidence = message->event();
00416
00417
00418 QString uid = incidence->uid();
00419 KCal::MailScheduler scheduler( mCalendar );
00420 if( !scheduler.acceptTransaction( incidence,
00421 (KCal::Scheduler::Method)message->method(),
00422 message->status() ) ) {
00423 KMessageBox::error( mView, i18n("Scheduling failed") );
00424 return false;
00425 }
00426
00427 mView->updateView();
00428 return true;
00429 }
00430
00431 QString KOGroupware::getFreeBusyString()
00432 {
00433 QDateTime start = QDateTime::currentDateTime();
00434 QDateTime end = start.addDays( KOPrefs::instance()->mPublishFreeBusyDays );
00435
00436 FreeBusy freebusy( mCalendar, start, end );
00437 freebusy.setOrganizer( KOPrefs::instance()->email() );
00438
00439
00440
00441
00442
00443 return mFormat.createScheduleMessage( &freebusy, Scheduler::Publish );
00444 }
00445
00446 #if 0
00447
00452 void KOGroupware::publishFreeBusy()
00453 {
00454 if( !KOPrefs::instance()->mPublishFreeBusy ) {
00455 KMessageBox::sorry( 0, i18n( "<qt>Publishing free/busy lists has been disabled. If you are sure that you want to publish your free/busy list, go to <em>Settings/Configure KOrganizer.../Groupware</em> and turn on publishing free/busy lists.</qt>" ) );
00456 return;
00457 }
00458
00459 QString messageText = getFreeBusyString();
00460
00461
00462
00463
00464
00465
00466 messageText = messageText.replace( QRegExp( "ORGANIZER\\s*:MAILTO:" ), "ORGANIZER:" );
00467
00468
00469
00470
00471 QString emailHost = KOPrefs::instance()->email().mid( KOPrefs::instance()->email().find( '@' ) + 1 );
00472
00473
00474 KTempFile tempFile;
00475 tempFile.setAutoDelete( true );
00476 QTextStream* textStream = tempFile.textStream();
00477 if( textStream ) {
00478 *textStream << messageText;
00479 tempFile.close();
00480
00481
00482 KURL targetURL;
00483 if( KOPrefs::instance()->mPublishKolab ) {
00484
00485 QString server;
00486 if( KOPrefs::instance()->mPublishKolabServer == "%SERVER%" ||
00487 KOPrefs::instance()->mPublishKolabServer.isEmpty() )
00488 server = emailHost;
00489 else
00490 server = KOPrefs::instance()->mPublishKolabServer;
00491
00492 targetURL.setProtocol( "webdavs" );
00493 targetURL.setHost( server );
00494 targetURL.setPath( "/freebusy/" + KOPrefs::instance()->mPublishUserName + ".vfb" );
00495 targetURL.setUser( KOPrefs::instance()->mPublishUserName );
00496 targetURL.setPass( KOPrefs::instance()->mPublishPassword );
00497 } else {
00498
00499 targetURL = KOPrefs::instance()->mPublishAnyURL.replace( "%SERVER%", emailHost );
00500 targetURL.setUser( KOPrefs::instance()->mPublishUserName );
00501 targetURL.setPass( KOPrefs::instance()->mPublishPassword );
00502 }
00503
00504 if( !KIO::NetAccess::upload( tempFile.name(), targetURL ) ) {
00505 KMessageBox::sorry( 0,
00506 i18n( "<qt>The software could not upload your free/busy list to the URL %1. There might be a problem with the access rights, or you specified an incorrect URL. The system said: <em>%2</em>.<br>Please check the URL or contact your system administrator.</qt>" ).arg( targetURL.url() ).arg( KIO::NetAccess::lastErrorString() ) );
00507 }
00508 }
00509 }
00510 #endif
00511
00512 FBDownloadJob::FBDownloadJob( const QString& email, const KURL& url, KOGroupware* kogroupware, const char* name )
00513 : QObject( kogroupware, name ), mKogroupware(kogroupware), mEmail( email )
00514 {
00515 KIO::Job* job = KIO::get( url, false, false );
00516 connect( job, SIGNAL( result( KIO::Job* ) ),
00517 this, SLOT( slotResult( KIO::Job* ) ) );
00518 connect( job, SIGNAL( data( KIO::Job*, const QByteArray& ) ),
00519 this, SLOT( slotData( KIO::Job*, const QByteArray& ) ) );
00520 }
00521
00522 FBDownloadJob::~FBDownloadJob()
00523 {
00524
00525 }
00526
00527 void FBDownloadJob::slotData( KIO::Job*, const QByteArray& data)
00528 {
00529 QByteArray tmp = data;
00530 tmp.resize( tmp.size() + 1 );
00531 tmp[tmp.size()-1] = 0;
00532 mFBData += tmp;
00533 }
00534
00535 void FBDownloadJob::slotResult( KIO::Job* job )
00536 {
00537 if( job->error() ) {
00538 kdDebug(5850) << "FBDownloadJob::slotResult() job error :-(" << endl;
00539 }
00540
00541 FreeBusy* fb = mKogroupware->parseFreeBusy( mFBData );
00542 emit fbDownloaded( mEmail, fb );
00543 delete this;
00544 }
00545
00546 bool KOGroupware::downloadFreeBusyData( const QString& email, QObject* receiver, const char* member )
00547 {
00548
00549 if( !KOPrefs::instance()->mRetrieveFreeBusy )
00550 return false;
00551
00552
00553
00554 int emailpos = email.find( '@' );
00555 if( emailpos == -1 )
00556 return false;
00557
00558
00559 QString emailName = email.left( emailpos );
00560 QString emailHost = email.mid( emailpos + 1 );
00561
00562
00563 KURL sourceURL;
00564 if( KOPrefs::instance()->mRetrieveKolab ) {
00565
00566 QString server;
00567 if( KOPrefs::instance()->mRetrieveKolabServer == "%SERVER%" ||
00568 KOPrefs::instance()->mRetrieveKolabServer.isEmpty() )
00569 server = emailHost;
00570 else
00571 server = KOPrefs::instance()->mRetrieveKolabServer;
00572
00573 sourceURL.setProtocol( "webdavs" );
00574 sourceURL.setHost( server );
00575 sourceURL.setPass( KOPrefs::instance()->mRetrievePassword );
00576 sourceURL.setUser( KOPrefs::instance()->mRetrieveUserName );
00577 sourceURL.setPath( QString::fromLatin1( "/freebusy/" ) + emailName +
00578 QString::fromLatin1( ".vfb" ) );
00579 } else {
00580
00581 QString anyurl = KOPrefs::instance()->mRetrieveAnyURL;
00582 if( anyurl.contains( "%SERVER%" ) )
00583 anyurl.replace( "%SERVER%", emailHost );
00584 sourceURL = anyurl;
00585 }
00586
00587 FBDownloadJob* job = new FBDownloadJob( email, sourceURL, this, "fb_download_job" );
00588 connect( job, SIGNAL( fbDownloaded( const QString&, FreeBusy*) ),
00589 receiver, member );
00590
00591 return true;
00592 }
00593
00594 KCal::FreeBusy* KOGroupware::parseFreeBusy( const QCString& data )
00595 {
00596 KCal::FreeBusy* fb = 0;
00597 QString freeBusyVCal = QString::fromUtf8(data);
00598 KCal::ScheduleMessage *message = mFormat.parseScheduleMessage( mCalendar,
00599 freeBusyVCal );
00600 if( message ) {
00601 KCal::IncidenceBase* event = message->event();
00602 Q_ASSERT( event );
00603
00604 if( event ) {
00605
00606
00607
00608
00609
00610 KCal::MailScheduler scheduler( mCalendar );
00611 scheduler.acceptTransaction( event,
00612 (KCal::Scheduler::Method)message->method(),
00613 message->status() );
00614 fb = dynamic_cast<KCal::FreeBusy*>( event );
00615 Q_ASSERT( fb );
00616 }
00617 }
00618 return fb;
00619 }
00620
00621
00622
00623
00624
00625
00626
00627
00628 bool KOGroupware::sendICalMessage( QWidget* parent,
00629 KCal::Scheduler::Method method,
00630 Incidence* incidence, bool isDeleting )
00631 {
00632 bool isOrganizer = KOPrefs::instance()->email() == incidence->organizer();
00633
00634 int rc = 0;
00635 if( isOrganizer ) {
00636
00637 bool otherPeople = false;
00638 Attendee::List attendees = incidence->attendees();
00639 Attendee::List::ConstIterator it;
00640 for ( it = attendees.begin(); it != attendees.end(); ++it ) {
00641
00642 if( (*it)->email() != KOPrefs::instance()->email() ) {
00643 otherPeople = true;
00644 break;
00645 }
00646 }
00647 if( !otherPeople )
00648
00649 return true;
00650
00651 QString type;
00652 if( incidence->type() == "Event") type = i18n("event");
00653 else if( incidence->type() == "Todo" ) type = i18n("task");
00654 else if( incidence->type() == "Journal" ) type = i18n("journal entry");
00655 else type = incidence->type();
00656 QString txt = i18n("This %1 includes other people. "
00657 "Should email be sent out to the attendees?").arg(type);
00658 rc = KMessageBox::questionYesNoCancel( parent, txt, i18n("Group scheduling email") );
00659 } else if( incidence->type() == "Todo" ) {
00660 if( method == Scheduler::Request )
00661
00662 method = Scheduler::Reply;
00663
00664
00665 QString txt = i18n("Do you want to send a status update to the organizer of this task?");
00666 rc = KMessageBox::questionYesNo( parent, txt );
00667 } else if( incidence->type() == "Event" ) {
00668
00669
00670 QString txt;
00671 if( isDeleting )
00672 txt = i18n("You are not the organizer of this event. "
00673 "Deleting it will bring your calendar out of sync "
00674 "with the organizers calendar. Do you really want to delete it?");
00675 else
00676 txt = i18n("You are not the organizer of this event. "
00677 "Editing it will bring your calendar out of sync "
00678 "with the organizers calendar. Do you really want to edit it?");
00679 rc = KMessageBox::questionYesNo( parent, txt );
00680 return ( rc == KMessageBox::Yes );
00681 } else {
00682 qFatal( "Some unimplemented thing happened" );
00683 }
00684
00685 if( rc == KMessageBox::Yes ) {
00686
00687 if( incidence->summary().isEmpty() )
00688 incidence->setSummary( i18n("<No summary given>") );
00689
00690
00691 KCal::MailScheduler scheduler( mCalendar );
00692 scheduler.performTransaction( incidence, method );
00693
00694 return true;
00695 } else if( rc == KMessageBox::No )
00696 return true;
00697 else
00698 return false;
00699 }
00700
00701 #include "kogroupware.moc"