From 22389489c059212986eb79ebe121f71cc0cb4f9e Mon Sep 17 00:00:00 2001 From: David Faure Date: Fri, 18 Jun 2004 23:38:22 +0000 Subject: [PATCH] * Set contents type of the resource folders (contacts/notes/etc.). Amazing that this wasn't done before :) * Store contents type on server using a "set annotations" job. Currently using /comment, since imapd doesn't support /vendor/* yet. Discussion is under way. svn path=/branches/proko2/kdepim/; revision=321827 --- kmailicalifaceimpl.cpp | 17 ++++--- kmailicalifaceimpl.h | 9 ++-- kmfoldercachedimap.cpp | 113 +++++++++++++++++++++++++++++++---------- kmfoldercachedimap.h | 1 + 4 files changed, 102 insertions(+), 38 deletions(-) diff --git a/kmailicalifaceimpl.cpp b/kmailicalifaceimpl.cpp index 91008726a..04f753cd1 100644 --- a/kmailicalifaceimpl.cpp +++ b/kmailicalifaceimpl.cpp @@ -384,7 +384,7 @@ bool KMailICalIfaceImpl::update( const QString& resource, // TODO: khz return false; } - + QString KMailICalIfaceImpl::getAttachment( const QString& filename ) { kdError(5006) << "NYI: KMailICalIfaceImpl::getAttachment()\n"; @@ -796,11 +796,11 @@ void KMailICalIfaceImpl::readConfig() cleanup(); // Set the new folders - mCalendar = initFolder( KFolderTreeItem::Calendar, "GCa" ); - mTasks = initFolder( KFolderTreeItem::Tasks, "GTa" ); - mJournals = initFolder( KFolderTreeItem::Journals, "GTa" ); - mContacts = initFolder( KFolderTreeItem::Contacts, "GCo" ); - mNotes = initFolder( KFolderTreeItem::Notes, "GNo" ); + mCalendar = initFolder( KFolderTreeItem::Calendar, "GCa", KMail::ContentsTypeCalendar ); + mTasks = initFolder( KFolderTreeItem::Tasks, "GTa", KMail::ContentsTypeTask ); + mJournals = initFolder( KFolderTreeItem::Journals, "GTa", KMail::ContentsTypeJournal ); + mContacts = initFolder( KFolderTreeItem::Contacts, "GCo", KMail::ContentsTypeContact ); + mNotes = initFolder( KFolderTreeItem::Notes, "GNo", KMail::ContentsTypeNote ); // Connect the expunged signal connect( mCalendar, SIGNAL( expunged() ), this, SLOT( slotRefreshCalendar() ) ); @@ -829,7 +829,8 @@ void KMailICalIfaceImpl::slotRefreshContacts() { slotRefresh( "Contact" ); } void KMailICalIfaceImpl::slotRefreshNotes() { slotRefresh( "Notes" ); } KMFolder* KMailICalIfaceImpl::initFolder( KFolderTreeItem::Type itemType, - const char* typeString ) + const char* typeString, + KMail::FolderContentsType contentsType ) { // Figure out what type of folder this is supposed to be KMFolderType type = mFolderType; @@ -854,6 +855,8 @@ KMFolder* KMailICalIfaceImpl::initFolder( KFolderTreeItem::Type itemType, return 0; } folder->setType( typeString ); + folder->storage()->setContentsType( contentsType ); + folder->setSystemFolder( true ); folder->open(); diff --git a/kmailicalifaceimpl.h b/kmailicalifaceimpl.h index 5fac915cf..633d5292d 100644 --- a/kmailicalifaceimpl.h +++ b/kmailicalifaceimpl.h @@ -66,7 +66,7 @@ public: KURL getAttachment( const QString& resource, const QString& sernum, const QString& filename ); - + // This saves the iCals/vCards in the entries in the folder. // The format in the string list is uid, entry, uid, entry... bool update( const QString& type, const QString& folder, @@ -85,13 +85,13 @@ public: const QString& sernum, const QStringList& attachments, const QStringList& deletedAttachments ); - + bool deleteIncidenceKolab( const QString& resource, const QString& sernum ); QMap incidencesKolab( const QString& type, const QString& resource ); QMap subresourcesKolab( const QString& annotation ); - + // "Get" an attachment. This actually saves the attachment in a file // and returns a URL to it QString getAttachment( const QString& filename ); @@ -167,7 +167,8 @@ private slots: private: /** Helper function for initFolders. Initializes a single folder. */ - KMFolder* initFolder( KFolderTreeItem::Type itemType, const char* typeString ); + KMFolder* initFolder( KFolderTreeItem::Type itemType, const char* typeString, + KMail::FolderContentsType contentsType ); KMFolder* extraFolder( const QString& type, const QString& folder ); diff --git a/kmfoldercachedimap.cpp b/kmfoldercachedimap.cpp index 76a303476..a9626825f 100644 --- a/kmfoldercachedimap.cpp +++ b/kmfoldercachedimap.cpp @@ -144,6 +144,7 @@ KMFolderCachedImap::~KMFolderCachedImap() config->writeEntry("ImapPath", mImapPath); config->writeEntry("NoContent", mNoContent); config->writeEntry("ReadOnly", mReadOnly); + config->writeEntry("ContentsTypeChanged", mContentsTypeChanged); writeUidCache(); } @@ -175,7 +176,9 @@ void KMFolderCachedImap::readConfig() mReadOnly = config->readBoolEntry( "ReadOnly", false ); KMFolderMaildir::readConfig(); - mContentsTypeChanged = false; + + // Must be done afterwards since FolderStorage::readConfig sets mContentsTypeChanged + mContentsTypeChanged = config->readBoolEntry( "ContentsTypeChanged", false ); } void KMFolderCachedImap::remove() @@ -446,6 +449,17 @@ void KMFolderCachedImap::slotTroubleshoot() } } +// Name used for the various folder-contents-types in the folder annotations +// The index in this array is the KMail::FolderContentsType enum +static const char* s_contentsType2Annotation[] = { + "mail", + "event", + "contact", + "note", + "task", + "journal" +}; + void KMFolderCachedImap::serverSync( bool recurse ) { if( mSyncState != SYNC_STATE_INITIAL ) { @@ -744,21 +758,16 @@ void KMFolderCachedImap::serverSyncInternal() serverSyncInternal(); break; } else - mSyncState = SYNC_STATE_SET_ANNOTATIONS; - - case SYNC_STATE_SET_ANNOTATIONS: -#define KOLAB_FOLDERTYPE "/vendor/kolab/folder-type" -//#define KOLAB_FOLDERTYPE "/comment" //for testing, while cyrus-imap doesn't support /vendor/* - - mSyncState = SYNC_STATE_GET_ANNOTATIONS; - if ( mContentsTypeChanged ) { - // TODO - } + mSyncState = SYNC_STATE_GET_ANNOTATIONS; case SYNC_STATE_GET_ANNOTATIONS: - mSyncState = SYNC_STATE_SET_ACLS; +//#define KOLAB_FOLDERTYPE "/vendor/kolab/folder-type" +#define KOLAB_FOLDERTYPE "/comment" //for testing, while cyrus-imap doesn't support /vendor/* + mSyncState = SYNC_STATE_SET_ANNOTATIONS; - if( !noContent() && mAccount->hasAnnotationSupport() ) { + // First retrieve the annotation, so that we know we have to set it if it's not set. + // On the other hand, if the user changed the contentstype, there's no need to get first. + if( !noContent() && mAccount->hasAnnotationSupport() && !mContentsTypeChanged ) { newState( mProgress, i18n("Retrieving annotations")); // If in the future we want to retrieve more annotations, we should then write // a multiGetAnnotation job in annotationjobs.* @@ -777,6 +786,30 @@ void KMFolderCachedImap::serverSyncInternal() break; } + case SYNC_STATE_SET_ANNOTATIONS: + + mSyncState = SYNC_STATE_SET_ACLS; + if( mAccount->hasAnnotationSupport() && mContentsTypeChanged ) { + newState( mProgress, i18n("Setting annotations")); + // If in the future we want to set more annotations, we should then write + // a multiSetAnnotation job in annotationjobs.* + KURL url = mAccount->getUrl(); + url.setPath( imapPath() ); + QMap attributes; + QString annotation = s_contentsType2Annotation[mContentsType]; + attributes.insert( "value.shared", annotation ); + kdDebug(5006) << "Setting annotation for " << label() << " to " << annotation << endl; + KIO::SimpleJob* job = + AnnotationJobs::setAnnotation( mAccount->slave(), url, KOLAB_FOLDERTYPE, attributes ); + ImapAccountBase::jobData jd( url.url(), folder() ); + jd.cancellable = true; // we can always do so later + mAccount->insertJob(job, jd); + + connect(job, SIGNAL(result(KIO::Job *)), + SLOT(slotSetAnnotationResult(KIO::Job *))); + break; + } + case SYNC_STATE_SET_ACLS: mSyncState = SYNC_STATE_GET_ACLS; @@ -1637,22 +1670,12 @@ void KMFolderCachedImap::setContentsType( KMail::FolderContentsType type ) } } -// The index in this array is the KMail::FolderContentsType enum -static const struct { - const char* annotation; -} s_contentsType2Annotation[] = { - { "mail" }, - { "event" }, - { "contact" }, - { "note" }, - { "task" }, - { "journal" } -}; - void KMFolderCachedImap::slotGetAnnotationResult( KIO::Job* job ) { KMAcctCachedImap::JobIterator it = mAccount->findJob(job); + Q_ASSERT( it != mAccount->jobsEnd() ); if ( it == mAccount->jobsEnd() ) return; // Shouldn't happen + Q_ASSERT( (*it).parent == folder() ); if ( (*it).parent != folder() ) return; // Shouldn't happen AnnotationJobs::GetAnnotationJob* annjob = static_cast( job ); if ( annjob->error() ) { @@ -1662,8 +1685,14 @@ void KMFolderCachedImap::slotGetAnnotationResult( KIO::Job* job ) kdWarning(5006) << "slotGetAnnotationResult: " << job->errorString() << endl; } else { AnnotationList lst = annjob->annotations(); + // There are four cases. + // 1) no content-type on server -> set it + // 2) different content-type on server, locally changed -> set it (we don't even come here) + // 3) different (known) content-type on server, no local change -> get it + // 4) different unknown content-type on server, probably some older version -> set it + bool foundContentType = !lst.isEmpty(); for ( unsigned int i = 0 ; i < lst.size() ; ++ i ) { - //kdDebug(5006) << "Found annotation: " << lst[i].name << " = " << lst[i].value << endl; + kdDebug(5006) << "Found annotation: " << lst[i].name << " = " << lst[i].value << endl; if ( lst[i].name.startsWith( "value." ) ) { // value.priv or value.shared QString value = lst[i].value; QString type = value; @@ -1673,16 +1702,28 @@ void KMFolderCachedImap::slotGetAnnotationResult( KIO::Job* job ) type.truncate( dot ); subtype = value.mid( dot + 1 ); } + bool foundKnownType = false; for ( uint i = 0 ; i < sizeof s_contentsType2Annotation / sizeof *s_contentsType2Annotation; ++i ) { - if ( type == s_contentsType2Annotation[i].annotation ) { + if ( type == s_contentsType2Annotation[i] ) { + // Case 3: known content-type on server, get it setContentsType( static_cast( i ) ); mContentsTypeChanged = false; // we changed it, not the user + foundKnownType = true; break; } } + if ( !foundKnownType && !mReadOnly ) { + // Case 4: server has strange content-type, set it to what we need + mContentsTypeChanged = true; + } + // TODO handle subtype (inbox, drafts, sentitems, junkemail) } } + if ( !foundContentType && !mReadOnly ) { + // Case 1: server doesn't have content-type, set it + mContentsTypeChanged = true; + } } if (mAccount->slave()) mAccount->removeJob(job); @@ -1690,4 +1731,22 @@ void KMFolderCachedImap::slotGetAnnotationResult( KIO::Job* job ) serverSyncInternal(); } +void +KMFolderCachedImap::slotSetAnnotationResult(KIO::Job *job) +{ + KMAcctCachedImap::JobIterator it = mAccount->findJob(job); + if ( it == mAccount->jobsEnd() ) return; // Shouldn't happen + if ( (*it).parent != folder() ) return; // Shouldn't happen + + bool cont = true; + if ( job->error() ) + cont = mAccount->handleJobError( job, i18n( "Error while setting annotation: " ) + '\n' ); + else { + mContentsTypeChanged = false; + if (mAccount->slave()) mAccount->removeJob(job); + } + if ( cont ) + serverSyncInternal(); +} + #include "kmfoldercachedimap.moc" diff --git a/kmfoldercachedimap.h b/kmfoldercachedimap.h index c453cccfb..952d991db 100644 --- a/kmfoldercachedimap.h +++ b/kmfoldercachedimap.h @@ -235,6 +235,7 @@ protected slots: void slotConnectionResult( int errorCode, const QString& errorMsg ); void slotGetAnnotationResult( KIO::Job* ); + void slotSetAnnotationResult(KIO::Job *job); void slotReceivedUserRights( KMFolder* ); void slotReceivedACL( KMFolder*, KIO::Job*, const KMail::ACLList& );