Commit d8fd7a28 authored by Andras Mantia's avatar Andras Mantia
Browse files

1) Fix creation of new toplevel folders (and all its subfolder): it used to...

1) Fix creation of new toplevel folders (and all its subfolder): it used to generate a broken remote id and separtor ("i") causing weird problems.
2) Make sure toplevel imap folders are shown immediately, without a need to sync the account (workarounds an ETM bug 291143)
3) Warn the user if creating a folder failed on server-side and remove the folder locally. Otherwise if creation failed, it was impossible to create again a folder with the same name,
as it was already a folder with that name in the akonadi cache...
4) Make sure deleting folder "foo" doesn't deleted all folders starting with "foo" as it did before.
5) Just fix folder deletion. :) It could fail in certain cases.
6) Fix and adapt the tests.

Reporters of closed bugs: if you can still see the bug in 4.10.2, please reopen and state the details.

REVIEW: 109276
FIXED-IN: 4.10.2291143291143
BUG: 312435, 305269, 301088, 292418, 305987, 291143
parent 3eb827f7
......@@ -31,6 +31,8 @@
#include <kimap/setmetadatajob.h>
#include <kimap/subscribejob.h>
#include <akonadi/collectiondeletejob.h>
AddCollectionTask::AddCollectionTask( ResourceStateInterface::Ptr resource, QObject *parent )
: ResourceTask( DeferIfNoSession, resource, parent ), m_pendingJobs( 0 ), m_session(0)
{
......@@ -50,7 +52,7 @@ void AddCollectionTask::doStart( KIMAP::Session *session )
return;
}
const QChar separator = parentCollection().remoteId().at( 0 );
const QChar separator = separatorCharacter();
m_pendingJobs = 0;
m_session = session;
m_collection = collection();
......@@ -79,6 +81,8 @@ void AddCollectionTask::doStart( KIMAP::Session *session )
void AddCollectionTask::onCreateDone( KJob *job )
{
if ( job->error() ) {
//create on server failed, remove from the cache
new Akonadi::CollectionDeleteJob( m_collection );
cancelTask( job->errorString() );
} else {
// Automatically subscribe to newly created mailbox
......@@ -105,6 +109,7 @@ void AddCollectionTask::onSubscribeDone( KJob *job )
if ( !m_collection.hasAttribute<Akonadi::CollectionAnnotationsAttribute>() ) {
// we are finished
changeCommitted( m_collection );
synchronizeCollectionTree();
return;
}
......
......@@ -203,7 +203,7 @@ void ChangeCollectionTask::doStart( KIMAP::Session *session )
// This one goes last on purpose, we don't want the previous jobs
// we triggered to act on the wrong mailbox name
if ( parts().contains( "NAME" ) ) {
const QChar &separator = collection().remoteId().at( 0 );
const QChar separator = separatorCharacter();
m_collection.setName( m_collection.name().replace( separator, QString() ) );
m_collection.setRemoteId( separator + m_collection.name() );
......
......@@ -151,6 +151,11 @@ ImapResource::ImapResource( const QString &id )
Settings::self(); // make sure the D-Bus settings interface is up
new ResourceAdaptor( this );
setNeedsNetwork( needsNetwork() );
m_statusMessageTimer = new QTimer( this );
m_statusMessageTimer->setSingleShot( true );
connect( m_statusMessageTimer, SIGNAL(timeout()), SLOT(clearStatusMessage()) );
connect( this, SIGNAL(error(QString)), SLOT(showError(QString)) );
}
ImapResource::~ImapResource()
......@@ -682,6 +687,17 @@ QString ImapResource::dumpResourceToString() const
return QLatin1String("IMAP tasks: ") + ret;
}
void ImapResource::showError( const QString &message )
{
emit status( Akonadi::AgentBase::Idle, message );
m_statusMessageTimer->start( 1000*10 );
}
void ImapResource::clearStatusMessage()
{
emit status( Akonadi::AgentBase::Idle, "" );
}
// ----------------------------------------------------------------------------------
AKONADI_RESOURCE_MAIN( ImapResource )
......
......@@ -28,6 +28,9 @@
#include <akonadi/resourcebase.h>
#include <QPointer>
class QTimer;
class ResourceTask;
namespace KIMAP
{
......@@ -117,6 +120,9 @@ private Q_SLOTS:
void taskDestroyed( QObject *task );
void showError( const QString &message );
void clearStatusMessage();
private:
friend class ResourceState;
......@@ -130,6 +136,7 @@ private:
QPointer<SubscriptionDialog> mSubscriptions;
ImapIdleManager *m_idle;
bool m_fastSync;
QTimer *m_statusMessageTimer;
};
#endif
......@@ -30,7 +30,7 @@
RemoveCollectionRecursiveTask::RemoveCollectionRecursiveTask( ResourceStateInterface::Ptr resource, QObject *parent )
: ResourceTask( CancelIfNoSession, resource, parent ),
mSession( 0 ), mRunningDeleteJobs( 0 )
mSession( 0 ), mRunningDeleteJobs( 0 ), mFolderFound( false )
{
}
......@@ -42,6 +42,7 @@ void RemoveCollectionRecursiveTask::doStart( KIMAP::Session *session )
{
mSession = session;
mFolderFound = false;
KIMAP::ListJob *listJob = new KIMAP::ListJob( session );
listJob->setIncludeUnsubscribed( !isSubscriptionEnabled() );
listJob->setQueriedNamespaces( serverNamespaces() );
......@@ -63,21 +64,18 @@ void RemoveCollectionRecursiveTask::onMailBoxesReceived( const QList< KIMAP::Mai
for ( int i = 0; i < descriptors.size(); ++i ) {
const KIMAP::MailBoxDescriptor descriptor = descriptors[ i ];
if ( descriptor.name.startsWith( mailBox ) ) { // a sub folder to delete
if ( descriptor.name == mailBox || descriptor.name.startsWith( mailBox + descriptor.separator ) ) { // a sub folder to delete
const QStringList pathParts = descriptor.name.split( descriptor.separator );
foldersToDelete[ pathParts.count() ].append( descriptor );
}
}
if ( foldersToDelete.isEmpty() ) {
changeProcessed();
kDebug( 5327 ) << "Failed to find the folder to be deleted, resync the folder tree";
emitWarning( i18n( "Failed to find the folder to be deleted, restoring folder list." ) );
synchronizeCollectionTree();
return;
}
mFolderFound = true;
// Now start the actual deletion work
QMapIterator<int, QList<KIMAP::MailBoxDescriptor> > it( foldersToDelete );
it.toBack(); // we start with largest nesting value first
......@@ -135,12 +133,17 @@ void RemoveCollectionRecursiveTask::onDeleteJobDone( KJob* job )
void RemoveCollectionRecursiveTask::onJobDone( KJob* job )
{
if ( job->error() ) {
if ( job->error() ) {
changeProcessed();
kDebug( 5327 ) << "Failed to delete the folder, resync the folder tree";
emitWarning( i18n( "Failed to delete the folder, restoring folder list." ) );
synchronizeCollectionTree();
} else if ( !mFolderFound ) {
changeProcessed();
kDebug( 5327 ) << "Failed to find the folder to be deleted, resync the folder tree";
emitWarning( i18n( "Failed to find the folder to be deleted, restoring folder list." ) );
synchronizeCollectionTree();
}
}
......
......@@ -46,6 +46,7 @@ protected:
private:
KIMAP::Session *mSession;
uint mRunningDeleteJobs;
bool mFolderFound;
};
#endif
......@@ -374,4 +374,14 @@ void ResourceTask::kill()
cancelTask("killed");
}
const QChar ResourceTask::separatorCharacter() const
{
//If we create a toplevel folder, assume the separator to be '/'. This is not perfect, but detecting the right
//IMAP separator is not straightforward for toplevel folders, and fixes bug 292418 and maybe other, where
//subfolders end up with remote id's starting with "i" (the first letter of imap:// ...)
const QChar separator = ( parentCollection().remoteId() != rootRemoteId() ) ? parentCollection().remoteId().at( 0 ) : '/';
return separator;
}
#include "resourcetask.moc"
......@@ -115,6 +115,8 @@ protected:
void showInformationDialog( const QString &message, const QString &title, const QString &dontShowAgainName );
const QChar separatorCharacter() const;
static QList<QByteArray> toAkonadiFlags( const QList<QByteArray> &flags );
static QList<QByteArray> fromAkonadiFlags( const QList<QByteArray> &flags );
......
......@@ -180,7 +180,10 @@ QString DummyResourceState::rootRemoteId() const
QString DummyResourceState::mailBoxForCollection( const Akonadi::Collection &collection, bool ) const
{
return collection.remoteId().mid( 1 );
if ( collection.remoteId().startsWith('/') )
return collection.remoteId().mid( 1 );
else
return collection.remoteId();
}
void DummyResourceState::setIdleCollection( const Akonadi::Collection &collection )
......
......@@ -129,7 +129,7 @@ private slots:
<< "S: * LSUB ( \\HasChildren ) / INBOX/test1"
<< "S: * LSUB ( ) / INBOX/test1/test2"
<< "S: A000003 OK Completed ( 0.000 secs 26 calls )"
<< "C: A000004 SELECT \"INBOX/test1/test2\""
<< "C: A000004 SELECT \"INBOX/test1\""
<< "S: * FLAGS ( \\Answered \\Flagged \\Draft \\Deleted \\Seen )"
<< "S: * OK [ PERMANENTFLAGS ( \\Answered \\Flagged \\Draft \\Deleted \\Seen \\* ) ]"
<< "S: * 1 EXISTS"
......@@ -146,11 +146,11 @@ private slots:
<< "S: * 0 EXISTS"
<< "S: * 0 RECENT"
<< "S: A000006 OK Completed"
<< "C: A000007 DELETE \"INBOX/test1/test2\""
<< "C: A000007 DELETE \"INBOX/test1\""
<< "S: * 0 EXISTS"
<< "S: * 0 RECENT"
<< "S: A000007 OK Completed"
<< "C: A000008 SELECT \"INBOX/test1\""
<< "C: A000008 SELECT \"INBOX/test1/test2\""
<< "S: * FLAGS ( \\Answered \\Flagged \\Draft \\Deleted \\Seen )"
<< "S: * OK [ PERMANENTFLAGS ( \\Answered \\Flagged \\Draft \\Deleted \\Seen \\* ) ]"
<< "S: * 1 EXISTS"
......@@ -166,7 +166,7 @@ private slots:
<< "S: * 0 EXISTS"
<< "S: * 0 RECENT"
<< "S: A000010 OK Completed"
<< "C: A000011 DELETE \"INBOX/test1\""
<< "C: A000011 DELETE \"INBOX/test1/test2\""
<< "S: * 0 EXISTS"
<< "S: * 0 RECENT"
<< "S: A000011 OK Completed";
......@@ -208,7 +208,9 @@ private slots:
state->setCollection( collection );
RemoveCollectionRecursiveTask *task = new RemoveCollectionRecursiveTask( state );
task->start( &pool );
QTest::qWait( 100 );
QEventLoop loop;
connect( task, SIGNAL(destroyed(QObject*)), &loop, SLOT(quit()) );
loop.exec();
QCOMPARE( state->calls().count(), callNames.size() );
for ( int i = 0; i < callNames.size(); i++ ) {
......
Supports Markdown
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment