diff options
Diffstat (limited to 'kresources/kolab/kcal/resourcekolab.cpp')
-rw-r--r-- | kresources/kolab/kcal/resourcekolab.cpp | 1342 |
1 files changed, 0 insertions, 1342 deletions
diff --git a/kresources/kolab/kcal/resourcekolab.cpp b/kresources/kolab/kcal/resourcekolab.cpp deleted file mode 100644 index 44c13fd2b..000000000 --- a/kresources/kolab/kcal/resourcekolab.cpp +++ /dev/null @@ -1,1342 +0,0 @@ -/* - This file is part of the kolab resource - the implementation of the - Kolab storage format. See www.kolab.org for documentation on this. - - Copyright (c) 2004 Bo Thorsen <[email protected]> - 2004 Till Adam <[email protected]> - - This library is free software; you can redistribute it and/or - modify it under the terms of the GNU Library General Public - License as published by the Free Software Foundation; either - version 2 of the License, or (at your option) any later version. - - This library is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - Library General Public License for more details. - - You should have received a copy of the GNU Library General Public License - along with this library; see the file COPYING.LIB. If not, write to - the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, - Boston, MA 02110-1301, USA. - - In addition, as a special exception, the copyright holders give - permission to link the code of this program with any edition of - the TQt library by Trolltech AS, Norway (or with modified versions - of TQt that use the same license as TQt), and distribute linked - combinations including the two. You must obey the GNU General - Public License in all respects for all of the code used other than - TQt. If you modify this file, you may extend this exception to - your version of the file, but you are not obligated to do so. If - you do not wish to do so, delete this exception statement from - your version. -*/ - -#include "resourcekolab.h" -#include "event.h" -#include "task.h" -#include "journal.h" - -#include <kio/observer.h> -#include <kio/uiserver_stub.h> -#include <kapplication.h> -#include <dcopclient.h> -#include <libtdepim/kincidencechooser.h> -#include <kabc/locknull.h> -#include <kmainwindow.h> -#include <klocale.h> -#include <kinputdialog.h> -#include <ktempfile.h> -#include <kmdcodec.h> - -#include <tqfile.h> -#include <tqobject.h> -#include <tqtimer.h> -#include <tqapplication.h> - -#include <assert.h> - -using namespace KCal; -using namespace Kolab; - -static const char* kmailCalendarContentsType = "Calendar"; -static const char* kmailTodoContentsType = "Task"; -static const char* kmailJournalContentsType = "Journal"; -static const char* eventAttachmentMimeType = "application/x-vnd.kolab.event"; -static const char* todoAttachmentMimeType = "application/x-vnd.kolab.task"; -static const char* journalAttachmentMimeType = "application/x-vnd.kolab.journal"; -static const char* incidenceInlineMimeType = "text/calendar"; - - -ResourceKolab::ResourceKolab( const TDEConfig *config ) - : ResourceCalendar( config ), ResourceKolabBase( "ResourceKolab-libkcal" ), - mCalendar( TQString::fromLatin1("UTC") ), mOpen( false ),mResourceChangedTimer( 0, - "mResourceChangedTimer" ), mBatchAddingInProgress( false ) -{ - if ( !config ) { - setResourceName( i18n( "Kolab Server" ) ); - } - setType( "imap" ); - connect( &mResourceChangedTimer, TQT_SIGNAL( timeout() ), - this, TQT_SLOT( slotEmitResourceChanged() ) ); -} - -ResourceKolab::~ResourceKolab() -{ - // The resource is deleted on exit (StdAddressBook's KStaticDeleter), - // and it wasn't closed before that, so close here to save the config. - if ( mOpen ) { - close(); - } -} - -void ResourceKolab::loadSubResourceConfig( TDEConfig& config, - const TQString& name, - const TQString& label, - bool writable, - bool alarmRelevant, - ResourceMap& subResource ) -{ - TDEConfigGroup group( &config, name ); - bool active = group.readBoolEntry( "Active", true ); - subResource.insert( name, Kolab::SubResource( active, writable, - alarmRelevant, label ) ); -} - -bool ResourceKolab::openResource( TDEConfig& config, const char* contentType, - ResourceMap& map ) -{ - // Read the subresource entries from KMail - TQValueList<KMailICalIface::SubResource> subResources; - if ( !kmailSubresources( subResources, contentType ) ) - return false; - map.clear(); - TQValueList<KMailICalIface::SubResource>::ConstIterator it; - for ( it = subResources.begin(); it != subResources.end(); ++it ) - loadSubResourceConfig( config, (*it).location, (*it).label, (*it).writable, - (*it).alarmRelevant, map ); - return true; -} - -bool ResourceKolab::doOpen() -{ - if ( mOpen ) - // Already open - return true; - mOpen = true; - - TDEConfig config( configFile() ); - config.setGroup( "General" ); - mProgressDialogIncidenceLimit = config.readNumEntry("ProgressDialogIncidenceLimit", 200); - - return openResource( config, kmailCalendarContentsType, mEventSubResources ) - && openResource( config, kmailTodoContentsType, mTodoSubResources ) - && openResource( config, kmailJournalContentsType, mJournalSubResources ); -} - -static void writeResourceConfig( TDEConfig& config, ResourceMap& map ) -{ - ResourceMap::ConstIterator it; - for ( it = map.begin(); it != map.end(); ++it ) { - config.setGroup( it.key() ); - config.writeEntry( "Active", it.data().active() ); - } -} - -void ResourceKolab::doClose() -{ - if ( !mOpen ) - // Not open - return; - mOpen = false; - - writeConfig(); -} - -bool ResourceKolab::loadSubResource( const TQString& subResource, - const char* mimetype ) -{ - int count = 0; - if ( !kmailIncidencesCount( count, mimetype, subResource ) ) { - kdError(5650) << "Communication problem in ResourceKolab::load()\n"; - return false; - } - - if ( !count ) - return true; - - const int nbMessages = 200; // read 200 mails at a time (see kabc resource) - - const TQString labelTxt = !strcmp(mimetype, "application/x-vnd.kolab.task") ? i18n( "Loading tasks..." ) - : !strcmp(mimetype, "application/x-vnd.kolab.journal") ? i18n( "Loading journals..." ) - : i18n( "Loading events..." ); - const bool useProgress = tqApp && tqApp->type() != TQApplication::Tty && count > mProgressDialogIncidenceLimit; - if ( useProgress ) - (void)::Observer::self(); // ensure kio_uiserver is running - UIServer_stub uiserver( "kio_uiserver", "UIServer" ); - int progressId = 0; - if ( useProgress ) { - progressId = uiserver.newJob( kapp->dcopClient()->appId(), true ); - uiserver.totalFiles( progressId, count ); - uiserver.infoMessage( progressId, labelTxt ); - uiserver.transferring( progressId, labelTxt ); - } - - for ( int startIndex = 0; startIndex < count; startIndex += nbMessages ) { - TQMap<TQ_UINT32, TQString> lst; - if ( !kmailIncidences( lst, mimetype, subResource, startIndex, nbMessages ) ) { - kdError(5650) << "Communication problem in ResourceKolab::load()\n"; - if ( progressId ) - uiserver.jobFinished( progressId ); - return false; - } - - { // for RAII scoping below - TemporarySilencer t( this ); - for( TQMap<TQ_UINT32, TQString>::ConstIterator it = lst.begin(); it != lst.end(); ++it ) { - addIncidence( mimetype, it.data(), subResource, it.key() ); - } - } - if ( progressId ) { - uiserver.processedFiles( progressId, startIndex ); - uiserver.percent( progressId, 100 * startIndex / count ); - } - -// if ( progress.wasCanceled() ) { -// uiserver.jobFinished( progressId ); -// return false; -// } - } - - if ( progressId ) - uiserver.jobFinished( progressId ); - return true; -} - -bool ResourceKolab::doLoad() -{ - if (!mUidMap.isEmpty() ) { - emit resourceLoaded( this ); - return true; - } - mUidMap.clear(); - - bool result = loadAllEvents() & loadAllTodos() & loadAllJournals(); - if ( result ) { - emit resourceLoaded( this ); - } else { - // FIXME: anyone know if the resource correctly calls loadError() - // if it has one? - } - - return result; -} - -bool ResourceKolab::doLoadAll( ResourceMap& map, const char* mimetype ) -{ - bool rc = true; - for ( ResourceMap::ConstIterator it = map.begin(); it != map.end(); ++it ) { - if ( !it.data().active() ) - // This resource is disabled - continue; - - rc &= loadSubResource( it.key(), mimetype ); - } - return rc; -} - -bool ResourceKolab::loadAllEvents() -{ - removeIncidences( "Event" ); - mCalendar.deleteAllEvents(); - bool kolabStyle = doLoadAll( mEventSubResources, eventAttachmentMimeType ); - bool icalStyle = doLoadAll( mEventSubResources, incidenceInlineMimeType ); - return kolabStyle && icalStyle; -} - -bool ResourceKolab::loadAllTodos() -{ - removeIncidences( "Todo" ); - mCalendar.deleteAllTodos(); - bool kolabStyle = doLoadAll( mTodoSubResources, todoAttachmentMimeType ); - bool icalStyle = doLoadAll( mTodoSubResources, incidenceInlineMimeType ); - - return kolabStyle && icalStyle; -} - -bool ResourceKolab::loadAllJournals() -{ - removeIncidences( "Journal" ); - mCalendar.deleteAllJournals(); - bool kolabStyle = doLoadAll( mJournalSubResources, journalAttachmentMimeType ); - bool icalStyle = doLoadAll( mJournalSubResources, incidenceInlineMimeType ); - - return kolabStyle && icalStyle; -} - -void ResourceKolab::removeIncidences( const TQCString& incidenceType ) -{ - Kolab::UidMap::Iterator mapIt = mUidMap.begin(); - while ( mapIt != mUidMap.end() ) - { - Kolab::UidMap::Iterator it = mapIt++; - // Check the type of this uid: event, todo or journal. - // Need to look up in mCalendar for that. Given the implementation of incidence(uid), - // better call event(uid), todo(uid) etc. directly. - - // A faster but hackish way would probably be to check the type of the resource, - // like mEventSubResources.find( it.data().resource() ) != mEventSubResources.end() ? - const TQString& uid = it.key(); - if ( incidenceType == "Event" && mCalendar.event( uid ) ) - mUidMap.remove( it ); - else if ( incidenceType == "Todo" && mCalendar.todo( uid ) ) - mUidMap.remove( it ); - else if ( incidenceType == "Journal" && mCalendar.journal( uid ) ) - mUidMap.remove( it ); - } -} - -bool ResourceKolab::doSave() -{ - return true; - /* - return kmailTriggerSync( kmailCalendarContentsType ) - && kmailTriggerSync( kmailTodoContentsType ) - && kmailTriggerSync( kmailJournalContentsType ); - */ -} -void ResourceKolab::incidenceUpdatedSilent( KCal::IncidenceBase* incidencebase ) -{ - const TQString uid = incidencebase->uid(); - //kdDebug() << k_funcinfo << uid << endl; - - if ( mUidsPendingUpdate.contains( uid ) || mUidsPendingAdding.contains( uid ) ) { - /* We are currently processing this event ( removing and readding or - * adding it ). If so, ignore this update. Keep the last of these around - * and process once we hear back from KMail on this event. */ - mPendingUpdates.remove( uid ); - mPendingUpdates.insert( uid, incidencebase ); - return; - } - - { // start optimization - /** - KOrganizer and libkcal like calling two Incidence::updated() - for only one user change. That's because after a change, - IncidenceChanger calls incidence->setRevision( rev++ ); - which also calls Incidence::updated(). - - Lets ignore the first updated() and only send to kmail - the second. This makes things faster. - */ - - //IncidenceBase doesn't have revision(), downcast needed. - Incidence *i = dynamic_cast<Incidence*>( incidencebase ); - - if ( i ) { - bool ignoreThisUpdate = false; - - if ( !mLastKnownRevisions.contains( uid ) ) { - mLastKnownRevisions[uid] = i->revision(); - } - - // update the last known revision - if ( mLastKnownRevisions[uid] < i->revision() ) { - mLastKnownRevisions[uid] = i->revision(); - } else { - ignoreThisUpdate = true; - } - - if ( ignoreThisUpdate ) { - return; - } - } - } // end optimization - - TQString subResource; - TQ_UINT32 sernum = 0; - if ( mUidMap.contains( uid ) ) { - subResource = mUidMap[ uid ].resource(); - sernum = mUidMap[ uid ].serialNumber(); - mUidsPendingUpdate.append( uid ); - } - - sendKMailUpdate( incidencebase, subResource, sernum ); -} -void ResourceKolab::incidenceUpdated( KCal::IncidenceBase* incidencebase ) -{ - if ( incidencebase->isReadOnly() ) { - return; - } - - incidencebase->setSyncStatusSilent( KCal::Event::SYNCMOD ); - incidencebase->setLastModified( TQDateTime::currentDateTime() ); - - // we should probably update the revision number here, - // or internally in the Event itself when certain things change. - // need to verify with ical documentation. - incidenceUpdatedSilent( incidencebase ); -} - -void ResourceKolab::resolveConflict( KCal::Incidence* inc, const TQString& subresource, TQ_UINT32 sernum ) -{ - if ( !inc ) { - return; - } - - if ( !mResolveConflict ) { - // we should do no conflict resolution - delete inc; - return; - } - const TQString origUid = inc->uid(); - Incidence* local = mCalendar.incidence( origUid ); - Incidence* localIncidence = 0; - Incidence* addedIncidence = 0; - Incidence* result = 0; - if ( local ) { - if ( *local == *inc ) { - // real duplicate, remove the second one - result = local; - } else { - KIncidenceChooser* ch = new KIncidenceChooser(); - ch->setIncidence( local ,inc ); - if ( KIncidenceChooser::chooseMode == KIncidenceChooser::ask ) { - connect ( this, TQT_SIGNAL( useGlobalMode() ), ch, TQT_SLOT ( useGlobalMode() ) ); - if ( ch->exec() ) { - if ( KIncidenceChooser::chooseMode != KIncidenceChooser::ask ) { - emit useGlobalMode() ; - } - } - } - result = ch->getIncidence(); - delete ch; - } - } else { - // nothing there locally, just take the new one. Can't Happen (TM) - result = inc; - } - if ( result == local ) { - delete inc; - localIncidence = local; - } else if ( result == inc ) { - addedIncidence = inc; - } else if ( result == 0 ) { // take both - addedIncidence = inc; - addedIncidence->setSummary( i18n("Copy of: %1").arg( addedIncidence->summary() ) ); - addedIncidence->setUid( CalFormat::createUniqueId() ); - localIncidence = local; - } - const bool silent = mSilent; - mSilent = false; - if ( !localIncidence ) { - deleteIncidence( local ); // remove local from kmail - } - mUidsPendingDeletion.append( origUid ); - if ( addedIncidence ) { - sendKMailUpdate( addedIncidence, subresource, sernum ); - } else { - kmailDeleteIncidence( subresource, sernum );// remove new from kmail - } - mSilent = silent; -} -void ResourceKolab::addIncidence( const char* mimetype, const TQString& data, - const TQString& subResource, TQ_UINT32 sernum ) -{ - // This uses pointer comparison, so it only works if we use the static - // objects defined in the top of the file - if ( mimetype == eventAttachmentMimeType ) - addEvent( data, subResource, sernum ); - else if ( mimetype == todoAttachmentMimeType ) - addTodo( data, subResource, sernum ); - else if ( mimetype == journalAttachmentMimeType ) - addJournal( data, subResource, sernum ); - else if ( mimetype == incidenceInlineMimeType ) { - Incidence *inc = mFormat.fromString( data ); - addIncidence( inc, subResource, sernum ); - } -} - - -bool ResourceKolab::sendKMailUpdate( KCal::IncidenceBase* incidencebase, const TQString& subresource, - TQ_UINT32 sernum ) -{ - const TQString& type = incidencebase->type(); - const char* mimetype = 0; - TQString data; - bool isXMLStorageFormat = kmailStorageFormat( subresource ) == KMailICalIface::StorageXML; - if ( type == "Event" ) { - if( isXMLStorageFormat ) { - mimetype = eventAttachmentMimeType; - data = Kolab::Event::eventToXML( static_cast<KCal::Event *>(incidencebase), - mCalendar.timeZoneId() ); - } else { - mimetype = incidenceInlineMimeType; - data = mFormat.createScheduleMessage( static_cast<KCal::Event *>(incidencebase), - Scheduler::Request ); - } - } else if ( type == "Todo" ) { - if( isXMLStorageFormat ) { - mimetype = todoAttachmentMimeType; - data = Kolab::Task::taskToXML( static_cast<KCal::Todo *>(incidencebase), - mCalendar.timeZoneId() ); - } else { - mimetype = incidenceInlineMimeType; - data = mFormat.createScheduleMessage( static_cast<KCal::Todo *>(incidencebase), - Scheduler::Request ); - } - } else if ( type == "Journal" ) { - if( isXMLStorageFormat ) { - mimetype = journalAttachmentMimeType; - data = Kolab::Journal::journalToXML( static_cast<KCal::Journal *>(incidencebase ), - mCalendar.timeZoneId() ); - } else { - mimetype = incidenceInlineMimeType; - data = mFormat.createScheduleMessage( static_cast<KCal::Journal *>(incidencebase), - Scheduler::Request ); - } - } else { - kdWarning(5006) << "Can't happen: unhandled type=" << type << endl; - } - -// kdDebug() << k_funcinfo << "Data string:\n" << data << endl; - - KCal::Incidence* incidence = static_cast<KCal::Incidence *>( incidencebase ); - - KCal::Attachment::List atts = incidence->attachments(); - TQStringList attURLs, attMimeTypes, attNames; - TQValueList<KTempFile*> tmpFiles; - for ( KCal::Attachment::List::ConstIterator it = atts.constBegin(); it != atts.constEnd(); ++it ) { - if ( (*it)->isUri() ) { - continue; - } - KTempFile *tempFile = new KTempFile; - if ( tempFile->status() == 0 ) { // open ok - const TQByteArray decoded = (*it)->decodedData() ; - - tempFile->file()->writeBlock( decoded.data(), decoded.count() ); - KURL url; - url.setPath( tempFile->name() ); - attURLs.append( url.url() ); - attMimeTypes.append( (*it)->mimeType() ); - attNames.append( (*it)->label() ); - tempFile->close(); - tmpFiles.append( tempFile ); - } else { - kdWarning(5006) << "Cannot open temporary file for attachment"; - } - } - TQStringList deletedAtts; - if ( kmailListAttachments( deletedAtts, subresource, sernum ) ) { - for ( TQStringList::ConstIterator it = attNames.constBegin(); it != attNames.constEnd(); ++it ) { - deletedAtts.remove( *it ); - } - } - CustomHeaderMap customHeaders; - if ( incidence->schedulingID() != incidence->uid() ) { - customHeaders.insert( "X-Kolab-SchedulingID", incidence->schedulingID() ); - } - - TQString subject = incidencebase->uid(); - if ( !isXMLStorageFormat ) subject.prepend( "iCal " ); // conform to the old style - - // behold, sernum is an in-parameter - const bool rc = kmailUpdate( subresource, sernum, data, mimetype, subject, customHeaders, attURLs, attMimeTypes, attNames, deletedAtts ); - // update the serial number - if ( mUidMap.contains( incidencebase->uid() ) ) { - mUidMap[ incidencebase->uid() ].setSerialNumber( sernum ); - } - - for( TQValueList<KTempFile *>::Iterator it = tmpFiles.begin(); it != tmpFiles.end(); ++it ) { - (*it)->setAutoDelete( true ); - delete (*it); - } - - return rc; -} - -bool ResourceKolab::addIncidence( KCal::Incidence* incidence, const TQString& _subresource, - TQ_UINT32 sernum ) -{ - Q_ASSERT( incidence ); - if ( !incidence ) { - return false; - } - - kdDebug() << "Resourcekolab, adding incidence " - << incidence->summary() - << "; subresource = " << _subresource - << "; sernum = " << sernum - << "; mBatchAddingInProgress = " << mBatchAddingInProgress - << endl; - - TQString uid = incidence->uid(); - TQString subResource = _subresource; - - Kolab::ResourceMap *map = &mEventSubResources; // don't use a ref here! - - const TQString& type = incidence->type(); - if ( type == "Event" ) { - map = &mEventSubResources; - } else if ( type == "Todo" ) { - map = &mTodoSubResources; - } else if ( type == "Journal" ) { - map = &mJournalSubResources; - } else { - kdWarning() << "unknown type " << type << endl; - } - - if ( !mSilent ) { /* We got this one from the user, tell KMail. */ - // Find out if this event was previously stored in KMail - bool newIncidence = _subresource.isEmpty(); - if ( newIncidence ) { - ResourceType type = Incidences; - // Add a description of the incidence - TQString text = "<b><font size=\"+1\">"; - if ( incidence->type() == "Event" ) { - type = Events; - text += i18n( "Choose the folder where you want to store this event" ); - } else if ( incidence->type() == "Todo" ) { - type = Tasks; - text += i18n( "Choose the folder where you want to store this task" ); - } else { - text += i18n( "Choose the folder where you want to store this incidence" ); - } - text += "<font></b><br>"; - if ( !incidence->summary().isEmpty() ) - text += i18n( "<b>Summary:</b> %1" ).arg( incidence->summary() ) + "<br>"; - if ( !incidence->location().isEmpty() ) - text += i18n( "<b>Location:</b> %1" ).arg( incidence->location() ); - text += "<br>"; - if ( !incidence->doesFloat() ) - text += i18n( "<b>Start:</b> %1, %2" ) - .arg( incidence->dtStartDateStr(), incidence->dtStartTimeStr() ); - else - text += i18n( "<b>Start:</b> %1" ).arg( incidence->dtStartDateStr() ); - text += "<br>"; - if ( incidence->type() == "Event" ) { - Event* event = static_cast<Event*>( incidence ); - if ( event->hasEndDate() ) { - if ( !event->doesFloat() ) { - text += i18n( "<b>End:</b> %1, %2" ) - .arg( event->dtEndDateStr(), event->dtEndTimeStr() ); - } else { - text += i18n( "<b>End:</b> %1" ).arg( event->dtEndDateStr() ); - } - } - text += "<br>"; - } - - // Lets not warn the user 100 times that there's no writable resource - // and not ask 100 times which resource to use - if ( !mBatchAddingInProgress || !mLastUsedResources.contains( type ) ) { - subResource = findWritableResource( type, *map, text ); - mLastUsedResources[type] = subResource; - } else { - subResource = mLastUsedResources[type]; - } - - if ( subResource.isEmpty() ) { - switch( mErrorCode ) { - case NoWritableFound: - setException( new ErrorFormat( ErrorFormat::NoWritableFound ) ); - break; - case UserCancel: - setException( new ErrorFormat( ErrorFormat::UserCancel ) ); - break; - case NoError: - break; - } - } - } - - if ( subResource.isEmpty() ) { - endAddingIncidences(); // cleanup - kdDebug(5650) << "ResourceKolab: subResource is empty" << endl; - return false; - } - - mNewIncidencesMap.insert( uid, subResource ); - - if ( !sendKMailUpdate( incidence, subResource, sernum ) ) { - kdError(5650) << "Communication problem in ResourceKolab::addIncidence()\n"; - endAddingIncidences(); // cleanup - return false; - } else { - // KMail is doing it's best to add the event now, put a sticker on it, - // so we know it's one of our transient ones - mUidsPendingAdding.append( uid ); - - /* Add to the cache immediately if this is a new event coming from - * KOrganizer. It relies on the incidence being in the calendar when - * addIncidence returns. */ - if ( newIncidence || sernum == 0 ) { - mCalendar.addIncidence( incidence ); - incidence->registerObserver( this ); - } - } - } else { /* KMail told us */ - const bool ourOwnUpdate = mUidsPendingUpdate.contains( uid ); - kdDebug( 5650 ) << "addIncidence: ourOwnUpdate " << ourOwnUpdate << endl; - /* Check if we updated this one, which means kmail deleted and added it. - * We know the new state, so lets just not do much at all. The old incidence - * in the calendar remains valid, but the serial number changed, so we need to - * update that */ - if ( ourOwnUpdate ) { - mUidsPendingUpdate.remove( uid ); - mUidMap.remove( uid ); - mUidMap[ uid ] = StorageReference( subResource, sernum ); - } else { - /* This is a real add, from KMail, we didn't trigger this ourselves. - * If this uid already exists in this folder, do conflict resolution, - * unless the folder is read-only, in which case the user should not be - * offered a means of putting mails in a folder she'll later be unable to - * upload. Skip the incidence, in this case. */ - if ( mUidMap.contains( uid ) ) { - if ( mUidMap[ uid ].resource() == subResource ) { - if ( (*map)[ subResource ].writable() ) { - kdDebug( 5650 ) << "lets resolve the conflict " << endl; - resolveConflict( incidence, subResource, sernum ); - } else { - kdWarning( 5650 ) << "Duplicate event in a read-only folder detected! " - "Please inform the owner of the folder. " << endl; - } - return true; - } else { - // duplicate uid in a different folder, do the internal-uid tango - incidence->setSchedulingID( uid ); - - incidence->setUid( CalFormat::createUniqueId( ) ); - uid = incidence->uid(); - - /* Will be needed when kmail triggers a delete, so we don't delete the inocent - * incidence that's sharing the uid with this one */ - mOriginalUID2fakeUID[tqMakePair( incidence->schedulingID(), subResource )] = uid; - } - } - /* Add to the cache if the add didn't come from KOrganizer, in which case - * we've already added it, and listen to updates from KOrganizer for it. */ - if ( !mUidsPendingAdding.contains( uid ) ) { - mCalendar.addIncidence( incidence ); - incidence->registerObserver( this ); - } - if ( !subResource.isEmpty() && sernum != 0 ) { - mUidMap[ uid ] = StorageReference( subResource, sernum ); - incidence->setReadOnly( !(*map)[ subResource ].writable() ); - } - } - /* Check if there are updates for this uid pending and if so process them. */ - if ( KCal::IncidenceBase *update = mPendingUpdates.find( uid ) ) { - mSilent = false; // we do want to tell KMail - mPendingUpdates.remove( uid ); - incidenceUpdated( update ); - } else { - /* If the uid was added by KMail, KOrganizer needs to be told, so - * schedule emitting of the resourceChanged signal. */ - if ( !mUidsPendingAdding.contains( uid ) ) { - if ( !ourOwnUpdate ) mResourceChangedTimer.changeInterval( 100 ); - } else { - mUidsPendingAdding.remove( uid ); - } - } - - mNewIncidencesMap.remove( uid ); - } - return true; -} - -bool ResourceKolab::addEvent( KCal::Event *event ) -{ - return addEvent( event, TQString() ); -} - -bool ResourceKolab::addEvent( KCal::Event *event, const TQString &subResource ) -{ - if ( mUidMap.contains( event->uid() ) ) { - return true; //noop - } else { - return addIncidence( event, subResource, 0 ); - } -} - -void ResourceKolab::addEvent( const TQString& xml, const TQString& subresource, - TQ_UINT32 sernum ) -{ - KCal::Event* event = Kolab::Event::xmlToEvent( xml, mCalendar.timeZoneId(), this, subresource, sernum ); - Q_ASSERT( event ); - if ( event ) { - addIncidence( event, subresource, sernum ); - } -} - -bool ResourceKolab::deleteIncidence( KCal::Incidence* incidence ) -{ - if ( incidence->isReadOnly() ) { - return false; - } - - const TQString uid = incidence->uid(); - if( !mUidMap.contains( uid ) ) return false; // Odd - /* The user told us to delete, tell KMail */ - if ( !mSilent ) { - kmailDeleteIncidence( mUidMap[ uid ].resource(), - mUidMap[ uid ].serialNumber() ); - mUidsPendingDeletion.append( uid ); - incidence->unRegisterObserver( this ); - mCalendar.deleteIncidence( incidence ); - mUidMap.remove( uid ); - } else { - assert( false ); // If this still happens, something is very wrong - } - return true; -} - -bool ResourceKolab::deleteEvent( KCal::Event* event ) -{ - return deleteIncidence( event ); -} - -KCal::Event* ResourceKolab::event( const TQString& uid ) -{ - return mCalendar.event(uid); -} - -KCal::Event::List ResourceKolab::rawEvents( EventSortField sortField, SortDirection sortDirection ) -{ - return mCalendar.rawEvents( sortField, sortDirection ); -} - -KCal::Event::List ResourceKolab::rawEventsForDate( const TQDate& date, - EventSortField sortField, - SortDirection sortDirection ) -{ - return mCalendar.rawEventsForDate( date, sortField, sortDirection ); -} - -KCal::Event::List ResourceKolab::rawEventsForDate( const TQDateTime& qdt ) -{ - return mCalendar.rawEventsForDate( qdt ); -} - -KCal::Event::List ResourceKolab::rawEvents( const TQDate& start, - const TQDate& end, - bool inclusive ) -{ - return mCalendar.rawEvents( start, end, inclusive ); -} - -bool ResourceKolab::addTodo( KCal::Todo *todo ) -{ - return addTodo( todo, TQString() ); -} - -bool ResourceKolab::addTodo( KCal::Todo *todo, const TQString &subResource ) -{ - if ( mUidMap.contains( todo->uid() ) ) { - return true; //noop - } else { - return addIncidence( todo, subResource, 0 ); - } -} - -void ResourceKolab::addTodo( const TQString& xml, const TQString& subresource, - TQ_UINT32 sernum ) -{ - KCal::Todo* todo = Kolab::Task::xmlToTask( xml, mCalendar.timeZoneId(), this, subresource, sernum ); - Q_ASSERT( todo ); - if ( todo ) { - addIncidence( todo, subresource, sernum ); - } -} - -bool ResourceKolab::deleteTodo( KCal::Todo* todo ) -{ - return deleteIncidence( todo ); -} - -KCal::Todo* ResourceKolab::todo( const TQString& uid ) -{ - return mCalendar.todo( uid ); -} - -KCal::Todo::List ResourceKolab::rawTodos( TodoSortField sortField, SortDirection sortDirection ) -{ - return mCalendar.rawTodos( sortField, sortDirection ); -} - -KCal::Todo::List ResourceKolab::rawTodosForDate( const TQDate& date ) -{ - return mCalendar.rawTodosForDate( date ); -} - -bool ResourceKolab::addJournal( KCal::Journal *journal ) -{ - return addJournal( journal, TQString() ); -} - -bool ResourceKolab::addJournal( KCal::Journal *journal, const TQString &subResource ) -{ - if ( mUidMap.contains( journal->uid() ) ) - return true; //noop - else - return addIncidence( journal, subResource, 0 ); -} - -void ResourceKolab::addJournal( const TQString& xml, const TQString& subresource, - TQ_UINT32 sernum ) -{ - KCal::Journal* journal = - Kolab::Journal::xmlToJournal( xml, mCalendar.timeZoneId() ); - Q_ASSERT( journal ); - if( journal ) { - addIncidence( journal, subresource, sernum ); - } -} - -bool ResourceKolab::deleteJournal( KCal::Journal* journal ) -{ - return deleteIncidence( journal ); -} - -KCal::Journal* ResourceKolab::journal( const TQString& uid ) -{ - return mCalendar.journal(uid); -} - -KCal::Journal::List ResourceKolab::rawJournals( JournalSortField sortField, SortDirection sortDirection ) -{ - return mCalendar.rawJournals( sortField, sortDirection ); -} - -KCal::Journal::List ResourceKolab::rawJournalsForDate( const TQDate &date ) -{ - return mCalendar.rawJournalsForDate( date ); -} - -KCal::Alarm::List ResourceKolab::relevantAlarms( const KCal::Alarm::List &alarms ) -{ - KCal::Alarm::List relevantAlarms; - KCal::Alarm::List::ConstIterator it( alarms.begin() ); - while ( it != alarms.end() ) { - KCal::Alarm *a = (*it); - ++it; - const TQString &uid = a->parent()->uid(); - if ( mUidMap.contains( uid ) ) { - const TQString &sr = mUidMap[ uid ].resource(); - Kolab::SubResource *subResource = 0; - if ( mEventSubResources.contains( sr ) ) - subResource = &( mEventSubResources[ sr ] ); - else if ( mTodoSubResources.contains( sr ) ) - subResource = &( mTodoSubResources[ sr ] ); - assert( subResource ); - if ( subResource->alarmRelevant() ) - relevantAlarms.append ( a ); - else { - kdDebug(5650) << "Alarm skipped, not relevant." << endl; - } - } - } - return relevantAlarms; -} - - - -KCal::Alarm::List ResourceKolab::alarms( const TQDateTime& from, - const TQDateTime& to ) -{ - return relevantAlarms( mCalendar.alarms( from, to ) ); -} - -KCal::Alarm::List ResourceKolab::alarmsTo( const TQDateTime& to ) -{ - return relevantAlarms( mCalendar.alarmsTo(to) ); -} - -void ResourceKolab::setTimeZoneId( const TQString& tzid ) -{ - mCalendar.setTimeZoneId( tzid ); - mFormat.setTimeZone( mCalendar.timeZoneId(), !mCalendar.isLocalTime() ); -} - -bool ResourceKolab::fromKMailAddIncidence( const TQString& type, - const TQString& subResource, - TQ_UINT32 sernum, - int format, - const TQString& data ) -{ - bool rc = true; - TemporarySilencer t( this ); // RAII - if ( type != kmailCalendarContentsType && type != kmailTodoContentsType - && type != kmailJournalContentsType ) { - // Not ours - return false; - } - - if ( !subresourceActive( subResource ) ) { - return true; - } - - if ( format == KMailICalIface::StorageXML ) { - // If this data file is one of ours, load it here - if ( type == kmailCalendarContentsType ) { - addEvent( data, subResource, sernum ); - } else if ( type == kmailTodoContentsType ) { - addTodo( data, subResource, sernum ); - } else if ( type == kmailJournalContentsType ) { - addJournal( data, subResource, sernum ); - } else { - rc = false; - } - } else { - Incidence *inc = mFormat.fromString( data ); - if ( inc ) { - addIncidence( inc, subResource, sernum ); - } else { - rc = false; - } - } - return rc; -} - -void ResourceKolab::fromKMailDelIncidence( const TQString& type, - const TQString& subResource, - const TQString& uid ) -{ - if ( type != kmailCalendarContentsType && type != kmailTodoContentsType - && type != kmailJournalContentsType ) - // Not ours - return; - if ( !subresourceActive( subResource ) ) return; - - // Can't be in both, by contract - if ( mUidsPendingDeletion.find( uid ) != mUidsPendingDeletion.end() ) { - mUidsPendingDeletion.remove( mUidsPendingDeletion.find( uid ) ); - } else if ( mUidsPendingUpdate.contains( uid ) ) { - // It's good to know if was deleted, but we are waiting on a new one to - // replace it, so let's just sit tight. - } else { - TQString uidToUse; - - TQPair<TQString, TQString> p( uid, subResource ); - if ( mOriginalUID2fakeUID.contains( p ) ) { - // Incidence with the same uid in a different folder... - // use the UID that addIncidence(...) generated - uidToUse = mOriginalUID2fakeUID[p]; - } else { - uidToUse = uid; - } - - // We didn't trigger this, so KMail did, remove the reference to the uid - KCal::Incidence* incidence = mCalendar.incidence( uidToUse ); - if( incidence ) { - incidence->unRegisterObserver( this ); - mCalendar.deleteIncidence( incidence ); - } - mUidMap.remove( uidToUse ); - mOriginalUID2fakeUID.remove( p ); - mResourceChangedTimer.changeInterval( 100 ); - } -} - -void ResourceKolab::fromKMailRefresh( const TQString& type, - const TQString& /*subResource*/ ) -{ - // TODO: Only load the specified subResource - if ( type == "Calendar" ) - loadAllEvents(); - else if ( type == "Task" ) - loadAllTodos(); - else if ( type == "Journal" ) - loadAllJournals(); - else - kdWarning(5006) << "KCal Kolab resource: fromKMailRefresh: unknown type " << type << endl; - mResourceChangedTimer.changeInterval( 100 ); -} - -void ResourceKolab::fromKMailAddSubresource( const TQString& type, - const TQString& subResource, - const TQString& label, - bool writable, bool alarmRelevant ) -{ - ResourceMap* map = 0; - const char* mimetype = 0; - if ( type == kmailCalendarContentsType ) { - map = &mEventSubResources; - mimetype = eventAttachmentMimeType; - } else if ( type == kmailTodoContentsType ) { - map = &mTodoSubResources; - mimetype = todoAttachmentMimeType; - } else if ( type == kmailJournalContentsType ) { - map = &mJournalSubResources; - mimetype = journalAttachmentMimeType; - } else - // Not ours - return; - - if ( map->contains( subResource ) ) - // Already registered - return; - - TDEConfig config( configFile() ); - config.setGroup( subResource ); - - bool active = config.readBoolEntry( subResource, true ); - (*map)[ subResource ] = Kolab::SubResource( active, writable, - alarmRelevant, label ); - loadSubResource( subResource, mimetype ); - emit signalSubresourceAdded( this, type, subResource, label ); -} - -void ResourceKolab::fromKMailDelSubresource( const TQString& type, - const TQString& subResource ) -{ - ResourceMap* map = subResourceMap( type ); - if ( !map ) // not ours - return; - if ( map->contains( subResource ) ) - map->erase( subResource ); - else - // Not registered - return; - - // Delete from the config file - TDEConfig config( configFile() ); - config.deleteGroup( subResource ); - config.sync(); - - unloadSubResource( subResource ); - - emit signalSubresourceRemoved( this, type, subResource ); -} - -TQStringList ResourceKolab::subresources() const -{ - // Workaround: The ResourceView in KOrganizer wants to know this - // before it opens the resource :-( Make sure we are open - const_cast<ResourceKolab*>( this )->doOpen(); - return ( mEventSubResources.keys() - + mTodoSubResources.keys() - + mJournalSubResources.keys() ); -} - -const TQString -ResourceKolab::labelForSubresource( const TQString& subresource ) const -{ - if ( mEventSubResources.contains( subresource ) ) - return mEventSubResources[ subresource ].label(); - if ( mTodoSubResources.contains( subresource ) ) - return mTodoSubResources[ subresource ].label(); - if ( mJournalSubResources.contains( subresource ) ) - return mJournalSubResources[ subresource ].label(); - return subresource; -} - -void ResourceKolab::fromKMailAsyncLoadResult( const TQMap<TQ_UINT32, TQString>& map, - const TQString& type, - const TQString& folder ) -{ - TemporarySilencer t( this ); - for( TQMap<TQ_UINT32, TQString>::ConstIterator it = map.begin(); it != map.end(); ++it ) - addIncidence( type.latin1(), it.data(), folder, it.key() ); -} - -bool ResourceKolab::subresourceActive( const TQString& subresource ) const -{ - // Workaround: The ResourceView in KOrganizer wants to know this - // before it opens the resource :-( Make sure we are open - const_cast<ResourceKolab*>( this )->doOpen(); - - if ( mEventSubResources.contains( subresource ) ) - return mEventSubResources[ subresource ].active(); - if ( mTodoSubResources.contains( subresource ) ) - return mTodoSubResources[ subresource ].active(); - if ( mJournalSubResources.contains( subresource ) ) - return mJournalSubResources[ subresource ].active(); - - // Safe default bet: - kdDebug(5650) << "subresourceActive( " << subresource << " ): Safe bet\n"; - - return true; -} - -void ResourceKolab::setSubresourceActive( const TQString &subresource, bool v ) -{ - ResourceMap *map = 0; - const char* mimeType = 0; - if ( mEventSubResources.contains( subresource ) ) { - map = &mEventSubResources; - mimeType = eventAttachmentMimeType; - } - if ( mTodoSubResources.contains( subresource ) ) { - map = &mTodoSubResources; - mimeType = todoAttachmentMimeType; - } - if ( mJournalSubResources.contains( subresource ) ) { - map = &mJournalSubResources; - mimeType = journalAttachmentMimeType; - } - - if ( map && ( ( *map )[ subresource ].active() != v ) ) { - ( *map )[ subresource ].setActive( v ); - if ( v ) { - loadSubResource( subresource, mimeType ); - } else { - unloadSubResource( subresource ); - } - mResourceChangedTimer.changeInterval( 100 ); - } - TQTimer::singleShot( 0, this, TQT_SLOT(writeConfig()) ); -} - -bool ResourceKolab::subresourceWritable( const TQString& subresource ) const -{ - // Workaround: The ResourceView in KOrganizer wants to know this - // before it opens the resource :-( Make sure we are open - const_cast<ResourceKolab*>( this )->doOpen(); - - if ( mEventSubResources.contains( subresource ) ) - return mEventSubResources[ subresource ].writable(); - if ( mTodoSubResources.contains( subresource ) ) - return mTodoSubResources[ subresource ].writable(); - if ( mJournalSubResources.contains( subresource ) ) - return mJournalSubResources[ subresource ].writable(); - - return false; //better a safe default -} - -void ResourceKolab::slotEmitResourceChanged() -{ - kdDebug(5650) << "KCal Kolab resource: emitting resource changed " << endl; - mResourceChangedTimer.stop(); - emit resourceChanged( this ); -} - -KABC::Lock* ResourceKolab::lock() -{ - return new KABC::LockNull( true ); -} - -Kolab::ResourceMap* ResourceKolab::subResourceMap( const TQString& contentsType ) -{ - if ( contentsType == kmailCalendarContentsType ) { - return &mEventSubResources; - } else if ( contentsType == kmailTodoContentsType ) { - return &mTodoSubResources; - } else if ( contentsType == kmailJournalContentsType ) { - return &mJournalSubResources; - } - // Not ours - return 0; -} - - -/*virtual*/ -bool ResourceKolab::addSubresource( const TQString& resource, const TQString& parent ) -{ - kdDebug(5650) << "KCal Kolab resource - adding subresource: " << resource << endl; - TQString contentsType = kmailCalendarContentsType; - if ( !parent.isEmpty() ) { - if ( mEventSubResources.contains( parent ) ) - contentsType = kmailCalendarContentsType; - else if ( mTodoSubResources.contains( parent ) ) - contentsType = kmailTodoContentsType; - else if ( mJournalSubResources.contains( parent ) ) - contentsType = kmailJournalContentsType; - } else { - TQStringList contentTypeChoices; - contentTypeChoices << i18n("Calendar") << i18n("Tasks") << i18n("Journals"); - const TQString caption = i18n("Which kind of subresource should this be?"); - const TQString choice = KInputDialog::getItem( caption, TQString(), contentTypeChoices ); - if ( choice == contentTypeChoices[0] ) - contentsType = kmailCalendarContentsType; - else if ( choice == contentTypeChoices[1] ) - contentsType = kmailTodoContentsType; - else if ( choice == contentTypeChoices[2] ) - contentsType = kmailJournalContentsType; - } - - return kmailAddSubresource( resource, parent, contentsType ); -} - -/*virtual*/ -bool ResourceKolab::removeSubresource( const TQString& resource ) -{ - kdDebug(5650) << "KCal Kolab resource - removing subresource: " << resource << endl; - return kmailRemoveSubresource( resource ); -} - -/*virtual*/ -TQString ResourceKolab::subresourceIdentifier( Incidence *incidence ) -{ - TQString uid = incidence->uid(); - if ( mUidMap.contains( uid ) ) - return mUidMap[ uid ].resource(); - else - if ( mNewIncidencesMap.contains( uid ) ) - return mNewIncidencesMap[ uid ]; - else - return TQString(); -} - - -bool ResourceKolab::unloadSubResource( const TQString& subResource ) -{ - const bool silent = mSilent; - mSilent = true; - Kolab::UidMap::Iterator mapIt = mUidMap.begin(); - TQPtrList<KCal::Incidence> incidences; - while ( mapIt != mUidMap.end() ) - { - Kolab::UidMap::Iterator it = mapIt++; - const StorageReference ref = it.data(); - if ( ref.resource() != subResource ) continue; - // FIXME incidence() is expensive - KCal::Incidence* incidence = mCalendar.incidence( it.key() ); - if( incidence ) { - // register all observers first before actually deleting them - // in case of inter-incidence relations the other part will get - // the change notification otherwise - incidence->unRegisterObserver( this ); - incidences.append( incidence ); - } - mUidMap.remove( it ); - } - TQPtrListIterator<KCal::Incidence> it( incidences ); - for ( ; it.current(); ++it ) { - mCalendar.deleteIncidence( it.current() ); - } - mSilent = silent; - return true; -} - -TQString ResourceKolab::subresourceType( const TQString &resource ) -{ - if ( mEventSubResources.contains( resource ) ) - return "event"; - if ( mTodoSubResources.contains( resource ) ) - return "todo"; - if ( mJournalSubResources.contains( resource ) ) - return "journal"; - return TQString(); -} - -void ResourceKolab::writeConfig() -{ - TDEConfig config( configFile() ); - writeResourceConfig( config, mEventSubResources ); - writeResourceConfig( config, mTodoSubResources ); - writeResourceConfig( config, mJournalSubResources ); -} - -void ResourceKolab::beginAddingIncidences() -{ - mBatchAddingInProgress = true; -} - -void ResourceKolab::endAddingIncidences() -{ - mBatchAddingInProgress = false; - mLastUsedResources.clear(); -} - -#include "resourcekolab.moc" |